Commit 08a6b8e0 by Tobias Burnus Committed by Tobias Burnus

re PR fortran/34112 (Add $!DEC ATTRIBUTE support for 32bit Windows' STDCALL)

2009-06-28  Tobias Burnus  <burnus@net-b.de>
	    Francois-Xavier Coudert  <fxcoudert@gcc.gnu.org>

	PR fortran/34112
	* symbol.c (gfc_add_ext_attribute): New function.
	(gfc_get_sym_tree): New argument allow_subroutine.
	(gfc_get_symbol,gfc_get_ha_sym_tree,gen_cptr_param,gen_fptr_param
	gen_shape_param,generate_isocbinding_symbol): Use it.
	* decl.c (find_special): New argument allow_subroutine.
	(add_init_expr_to_sym,add_hidden_procptr_result,attr_decl1,
	match_procedure_in_type,gfc_match_final_decl): Use it.
	(gfc_match_gcc_attributes): New function.
	* gfortran.texi (Mixed-Language Programming): New section
	"GNU Fortran Compiler Directives".
	* gfortran.h (ext_attr_t): New struct.
	(symbol_attributes): Use it.
	(gfc_add_ext_attribute): New prototype.
	(gfc_get_sym_tree): Update pototype.
	* expr.c (gfc_check_pointer_assign): Check whether call
	convention is the same.
	* module.c (import_iso_c_binding_module, create_int_parameter,
	use_iso_fortran_env_module): Update gfc_get_sym_tree call.
	* scanner.c (skip_gcc_attribute): New function.
	(skip_free_comments,skip_fixed_comments): Use it.
	(gfc_next_char_literal): Support !GCC$ lines.
	* resolve.c (check_host_association): Update
	gfc_get_sym_tree call.
	* match.c (gfc_match_sym_tree,gfc_match_call): Update
	gfc_get_sym_tree call.
	* trans-decl.c (add_attributes_to_decl): New function.
	(gfc_get_symbol_decl,get_proc_pointer_decl,
	gfc_get_extern_function_decl,build_function_decl: Use it.
	* match.h (gfc_match_gcc_attributes): Add prototype.
	* parse.c (decode_gcc_attribute): New function.
	(next_free,next_fixed): Support !GCC$ lines.
	* primary.c (match_actual_arg,check_for_implicit_index,
	gfc_match_rvalue,gfc_match_rvalue): Update
	gfc_get_sym_tree call.

2009-06-28  Tobias Burnus  <burnus@net-b.de>

	PR fortran/34112
	* gfortran.dg/compiler-directive_1.f90: New test.
	* gfortran.dg/compiler-directive_2.f: New test.


Co-Authored-By: Francois-Xavier Coudert <fxcoudert@gcc.gnu.org>

From-SVN: r149036
parent 0948ccb2
2009-06-28 Tobias Burnus <burnus@net-b.de>
Francois-Xavier Coudert <fxcoudert@gcc.gnu.org>
PR fortran/34112
* symbol.c (gfc_add_ext_attribute): New function.
(gfc_get_sym_tree): New argument allow_subroutine.
(gfc_get_symbol,gfc_get_ha_sym_tree,gen_cptr_param,gen_fptr_param
gen_shape_param,generate_isocbinding_symbol): Use it.
* decl.c (find_special): New argument allow_subroutine.
(add_init_expr_to_sym,add_hidden_procptr_result,attr_decl1,
match_procedure_in_type,gfc_match_final_decl): Use it.
(gfc_match_gcc_attributes): New function.
* gfortran.texi (Mixed-Language Programming): New section
"GNU Fortran Compiler Directives".
* gfortran.h (ext_attr_t): New struct.
(symbol_attributes): Use it.
(gfc_add_ext_attribute): New prototype.
(gfc_get_sym_tree): Update pototype.
* expr.c (gfc_check_pointer_assign): Check whether call
convention is the same.
* module.c (import_iso_c_binding_module, create_int_parameter,
use_iso_fortran_env_module): Update gfc_get_sym_tree call.
* scanner.c (skip_gcc_attribute): New function.
(skip_free_comments,skip_fixed_comments): Use it.
(gfc_next_char_literal): Support !GCC$ lines.
* resolve.c (check_host_association): Update
gfc_get_sym_tree call.
* match.c (gfc_match_sym_tree,gfc_match_call): Update
gfc_get_sym_tree call.
* trans-decl.c (add_attributes_to_decl): New function.
(gfc_get_symbol_decl,get_proc_pointer_decl,
gfc_get_extern_function_decl,build_function_decl: Use it.
* match.h (gfc_match_gcc_attributes): Add prototype.
* parse.c (decode_gcc_attribute): New function.
(next_free,next_fixed): Support !GCC$ lines.
* primary.c (match_actual_arg,check_for_implicit_index,
gfc_match_rvalue,gfc_match_rvalue): Update
gfc_get_sym_tree call.
2009-06-28 Kaveh R. Ghazi <ghazi@caip.rutgers.edu> 2009-06-28 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
* gfortran.h: Define HAVE_mpc_pow. * gfortran.h: Define HAVE_mpc_pow.
......
...@@ -696,14 +696,18 @@ syntax: ...@@ -696,14 +696,18 @@ syntax:
(located in another namespace). */ (located in another namespace). */
static int static int
find_special (const char *name, gfc_symbol **result) find_special (const char *name, gfc_symbol **result, bool allow_subroutine)
{ {
gfc_state_data *s; gfc_state_data *s;
gfc_symtree *st;
int i; int i;
i = gfc_get_symbol (name, NULL, result); i = gfc_get_sym_tree (name, NULL, &st, allow_subroutine);
if (i == 0) if (i == 0)
goto end; {
*result = st ? st->n.sym : NULL;
goto end;
}
if (gfc_current_state () != COMP_SUBROUTINE if (gfc_current_state () != COMP_SUBROUTINE
&& gfc_current_state () != COMP_FUNCTION) && gfc_current_state () != COMP_FUNCTION)
...@@ -1204,7 +1208,7 @@ add_init_expr_to_sym (const char *name, gfc_expr **initp, locus *var_locus) ...@@ -1204,7 +1208,7 @@ add_init_expr_to_sym (const char *name, gfc_expr **initp, locus *var_locus)
gfc_expr *init; gfc_expr *init;
init = *initp; init = *initp;
if (find_special (name, &sym)) if (find_special (name, &sym, false))
return FAILURE; return FAILURE;
attr = sym->attr; attr = sym->attr;
...@@ -4103,11 +4107,11 @@ add_hidden_procptr_result (gfc_symbol *sym) ...@@ -4103,11 +4107,11 @@ add_hidden_procptr_result (gfc_symbol *sym)
{ {
gfc_symtree *stree; gfc_symtree *stree;
if (case1) if (case1)
gfc_get_sym_tree ("ppr@", gfc_current_ns, &stree); gfc_get_sym_tree ("ppr@", gfc_current_ns, &stree, false);
else if (case2) else if (case2)
{ {
gfc_symtree *st2; gfc_symtree *st2;
gfc_get_sym_tree ("ppr@", gfc_current_ns->parent, &stree); gfc_get_sym_tree ("ppr@", gfc_current_ns->parent, &stree, false);
st2 = gfc_new_symtree (&gfc_current_ns->sym_root, "ppr@"); st2 = gfc_new_symtree (&gfc_current_ns->sym_root, "ppr@");
st2->n.sym = stree->n.sym; st2->n.sym = stree->n.sym;
} }
...@@ -5539,7 +5543,7 @@ attr_decl1 (void) ...@@ -5539,7 +5543,7 @@ attr_decl1 (void)
if (m != MATCH_YES) if (m != MATCH_YES)
goto cleanup; goto cleanup;
if (find_special (name, &sym)) if (find_special (name, &sym, false))
return MATCH_ERROR; return MATCH_ERROR;
var_locus = gfc_current_locus; var_locus = gfc_current_locus;
...@@ -7375,7 +7379,7 @@ match_procedure_in_type (void) ...@@ -7375,7 +7379,7 @@ match_procedure_in_type (void)
} }
stree->n.tb = tb; stree->n.tb = tb;
if (gfc_get_sym_tree (target, gfc_current_ns, &tb->u.specific)) if (gfc_get_sym_tree (target, gfc_current_ns, &tb->u.specific, false))
return MATCH_ERROR; return MATCH_ERROR;
gfc_set_sym_referenced (tb->u.specific->n.sym); gfc_set_sym_referenced (tb->u.specific->n.sym);
...@@ -7618,3 +7622,101 @@ gfc_match_final_decl (void) ...@@ -7618,3 +7622,101 @@ gfc_match_final_decl (void)
return MATCH_YES; return MATCH_YES;
} }
const ext_attr_t ext_attr_list[] = {
{ "dllimport", EXT_ATTR_DLLIMPORT, "dllimport" },
{ "dllexport", EXT_ATTR_DLLEXPORT, "dllexport" },
{ "cdecl", EXT_ATTR_CDECL, "cdecl" },
{ "stdcall", EXT_ATTR_STDCALL, "stdcall" },
{ "fastcall", EXT_ATTR_FASTCALL, "fastcall" },
{ NULL, EXT_ATTR_LAST, NULL }
};
/* Match a !GCC$ ATTRIBUTES statement of the form:
!GCC$ ATTRIBUTES attribute-list :: var-name [, var-name] ...
When we come here, we have already matched the !GCC$ ATTRIBUTES string.
TODO: We should support all GCC attributes using the same syntax for
the attribute list, i.e. the list in C
__attributes(( attribute-list ))
matches then
!GCC$ ATTRIBUTES attribute-list ::
Cf. c-parser.c's c_parser_attributes; the data can then directly be
saved into a TREE.
As there is absolutely no risk of confusion, we should never return
MATCH_NO. */
match
gfc_match_gcc_attributes (void)
{
symbol_attribute attr;
char name[GFC_MAX_SYMBOL_LEN + 1];
unsigned id;
gfc_symbol *sym;
match m;
gfc_clear_attr (&attr);
for(;;)
{
char ch;
if (gfc_match_name (name) != MATCH_YES)
return MATCH_ERROR;
for (id = 0; id < EXT_ATTR_LAST; id++)
if (strcmp (name, ext_attr_list[id].name) == 0)
break;
if (id == EXT_ATTR_LAST)
{
gfc_error ("Unknown attribute in !GCC$ ATTRIBUTES statement at %C");
return MATCH_ERROR;
}
if (gfc_add_ext_attribute (&attr, id, &gfc_current_locus)
== FAILURE)
return MATCH_ERROR;
gfc_gobble_whitespace ();
ch = gfc_next_ascii_char ();
if (ch == ':')
{
/* This is the successful exit condition for the loop. */
if (gfc_next_ascii_char () == ':')
break;
}
if (ch == ',')
continue;
goto syntax;
}
if (gfc_match_eos () == MATCH_YES)
goto syntax;
for(;;)
{
m = gfc_match_name (name);
if (m != MATCH_YES)
return m;
if (find_special (name, &sym, true))
return MATCH_ERROR;
sym->attr.ext_attr |= attr.ext_attr;
if (gfc_match_eos () == MATCH_YES)
break;
if (gfc_match_char (',') != MATCH_YES)
goto syntax;
}
return MATCH_YES;
syntax:
gfc_error ("Syntax error in !GCC$ ATTRIBUTES statement at %C");
return MATCH_ERROR;
}
...@@ -3186,6 +3186,32 @@ gfc_check_pointer_assign (gfc_expr *lvalue, gfc_expr *rvalue) ...@@ -3186,6 +3186,32 @@ gfc_check_pointer_assign (gfc_expr *lvalue, gfc_expr *rvalue)
rvalue->symtree->name, &rvalue->where) == FAILURE) rvalue->symtree->name, &rvalue->where) == FAILURE)
return FAILURE; return FAILURE;
} }
/* Ensure that the calling convention is the same. As other attributes
such as DLLEXPORT may differ, one explicitly only tests for the
calling conventions. */
if (rvalue->expr_type == EXPR_VARIABLE
&& lvalue->symtree->n.sym->attr.ext_attr
!= rvalue->symtree->n.sym->attr.ext_attr)
{
symbol_attribute cdecl, stdcall, fastcall;
unsigned calls;
gfc_add_ext_attribute (&cdecl, (unsigned) EXT_ATTR_CDECL, NULL);
gfc_add_ext_attribute (&stdcall, (unsigned) EXT_ATTR_STDCALL, NULL);
gfc_add_ext_attribute (&fastcall, (unsigned) EXT_ATTR_FASTCALL, NULL);
calls = cdecl.ext_attr | stdcall.ext_attr | fastcall.ext_attr;
if ((calls & lvalue->symtree->n.sym->attr.ext_attr)
!= (calls & rvalue->symtree->n.sym->attr.ext_attr))
{
gfc_error ("Mismatch in the procedure pointer assignment "
"at %L: mismatch in the calling convention",
&rvalue->where);
return FAILURE;
}
}
/* TODO: Enable interface check for PPCs. */ /* TODO: Enable interface check for PPCs. */
if (is_proc_ptr_comp (rvalue, NULL)) if (is_proc_ptr_comp (rvalue, NULL))
return SUCCESS; return SUCCESS;
......
...@@ -619,6 +619,28 @@ CInteropKind_t; ...@@ -619,6 +619,28 @@ CInteropKind_t;
that the list is initialized. */ that the list is initialized. */
extern CInteropKind_t c_interop_kinds_table[]; extern CInteropKind_t c_interop_kinds_table[];
/* Structure and list of supported extension attributes. */
enum
{
EXT_ATTR_DLLIMPORT = 0,
EXT_ATTR_DLLEXPORT,
EXT_ATTR_STDCALL,
EXT_ATTR_CDECL,
EXT_ATTR_FASTCALL,
EXT_ATTR_LAST, EXT_ATTR_NUM = EXT_ATTR_LAST
};
typedef struct
{
const char *name;
unsigned id;
const char *middle_end_name;
}
ext_attr_t;
extern const ext_attr_t ext_attr_list[];
/* Symbol attribute structure. */ /* Symbol attribute structure. */
typedef struct typedef struct
{ {
...@@ -704,6 +726,9 @@ typedef struct ...@@ -704,6 +726,9 @@ typedef struct
unsigned alloc_comp:1, pointer_comp:1, proc_pointer_comp:1, unsigned alloc_comp:1, pointer_comp:1, proc_pointer_comp:1,
private_comp:1, zero_comp:1; private_comp:1, zero_comp:1;
/* Attributes set by compiler extensions (!GCC$ ATTRIBUTES). */
unsigned ext_attr:EXT_ATTR_NUM;
/* The namespace where the VOLATILE attribute has been set. */ /* The namespace where the VOLATILE attribute has been set. */
struct gfc_namespace *volatile_ns; struct gfc_namespace *volatile_ns;
} }
...@@ -2299,6 +2324,7 @@ gfc_try gfc_set_default_type (gfc_symbol *, int, gfc_namespace *); ...@@ -2299,6 +2324,7 @@ gfc_try gfc_set_default_type (gfc_symbol *, int, gfc_namespace *);
void gfc_set_sym_referenced (gfc_symbol *); void gfc_set_sym_referenced (gfc_symbol *);
gfc_try gfc_add_attribute (symbol_attribute *, locus *); gfc_try gfc_add_attribute (symbol_attribute *, locus *);
gfc_try gfc_add_ext_attribute (symbol_attribute *, unsigned, locus *);
gfc_try gfc_add_allocatable (symbol_attribute *, locus *); gfc_try gfc_add_allocatable (symbol_attribute *, locus *);
gfc_try gfc_add_dimension (symbol_attribute *, const char *, locus *); gfc_try gfc_add_dimension (symbol_attribute *, const char *, locus *);
gfc_try gfc_add_external (symbol_attribute *, locus *); gfc_try gfc_add_external (symbol_attribute *, locus *);
...@@ -2379,7 +2405,7 @@ gfc_try verify_bind_c_derived_type (gfc_symbol *); ...@@ -2379,7 +2405,7 @@ gfc_try verify_bind_c_derived_type (gfc_symbol *);
gfc_try verify_com_block_vars_c_interop (gfc_common_head *); gfc_try verify_com_block_vars_c_interop (gfc_common_head *);
void generate_isocbinding_symbol (const char *, iso_c_binding_symbol, const char *); void generate_isocbinding_symbol (const char *, iso_c_binding_symbol, const char *);
gfc_symbol *get_iso_c_sym (gfc_symbol *, char *, char *, int); gfc_symbol *get_iso_c_sym (gfc_symbol *, char *, char *, int);
int gfc_get_sym_tree (const char *, gfc_namespace *, gfc_symtree **); int gfc_get_sym_tree (const char *, gfc_namespace *, gfc_symtree **, bool);
int gfc_get_ha_symbol (const char *, gfc_symbol **); int gfc_get_ha_symbol (const char *, gfc_symbol **);
int gfc_get_ha_sym_tree (const char *, gfc_symtree **); int gfc_get_ha_sym_tree (const char *, gfc_symtree **);
......
...@@ -1851,6 +1851,7 @@ c ...@@ -1851,6 +1851,7 @@ c
@menu @menu
* Interoperability with C:: * Interoperability with C::
* GNU Fortran Compiler Directives::
* Non-Fortran Main Program:: * Non-Fortran Main Program::
@end menu @end menu
...@@ -2097,6 +2098,60 @@ C-interoperable @code{OPTIONAL} and for assumed-rank and assumed-type ...@@ -2097,6 +2098,60 @@ C-interoperable @code{OPTIONAL} and for assumed-rank and assumed-type
dummy arguments. However, the TR has neither been approved nor implemented dummy arguments. However, the TR has neither been approved nor implemented
in GNU Fortran; therefore, these features are not yet available. in GNU Fortran; therefore, these features are not yet available.
@node GNU Fortran Compiler Directives
@section GNU Fortran Compiler Directives
The Fortran standard standard describes how a conforming program shall
behave; however, the exact implementation is not standardized. In order
to allow the user to choose specific implementation details, compiler
directives can be used to set attributes of variables and procedures
which are not part of the standard. Whether a given attribute is
supported and its exact effects depend on both the operating system and
on the processor; see
@ref{Top,,C Extensions,gcc,Using the GNU Compiler Collection (GCC)}
for details.
For procedures and procedure pointers, the following attributes can
be used to change the calling convention:
@itemize
@item @code{CDECL} -- standard C calling convention
@item @code{STDCALL} -- convention where the called procedure pops the stack
@item @code{FASTCALL} -- part of the arguments are passed via registers
instead using the stack
@end itemize
Besides changing the calling convention, the attributes also influence
the decoration of the symbol name, e.g., by a leading underscore or by
a trailing at-sign followed by the number of bytes on the stack. When
assigning a procedure to a procedure pointer, both should use the same
calling convention.
On some systems, procedures and global variables (module variables and
@code{COMMON} blocks) need special handling to be accessible when they
are in a shared library. The following attributes are available:
@itemize
@item @code{DLLEXPORT} -- provide a global pointer to a pointer in the DLL
@item @code{DLLIMPORT} -- reference the function or variable using a global pointer
@end itemize
The attributes are specified using the syntax
@code{!GCC$ ATTRIBUTES} @var{attribute-list} @code{::} @var{variable-list}
where in free-form source code only whitespace is allowed before @code{!GCC$}
and in fixed-form source code @code{!GCC$}, @code{cGCC$} or @code{*GCC$} shall
start in the first column.
For procedures, the compiler directives shall be placed into the body
of the procedure; for variables and procedure pointers, they shall be in
the same declaration part as the variable or procedure pointer.
@node Non-Fortran Main Program @node Non-Fortran Main Program
@section Non-Fortran Main Program @section Non-Fortran Main Program
......
...@@ -674,7 +674,7 @@ gfc_match_sym_tree (gfc_symtree **matched_symbol, int host_assoc) ...@@ -674,7 +674,7 @@ gfc_match_sym_tree (gfc_symtree **matched_symbol, int host_assoc)
return (gfc_get_ha_sym_tree (buffer, matched_symbol)) return (gfc_get_ha_sym_tree (buffer, matched_symbol))
? MATCH_ERROR : MATCH_YES; ? MATCH_ERROR : MATCH_YES;
if (gfc_get_sym_tree (buffer, NULL, matched_symbol)) if (gfc_get_sym_tree (buffer, NULL, matched_symbol, false))
return MATCH_ERROR; return MATCH_ERROR;
return MATCH_YES; return MATCH_YES;
...@@ -2711,7 +2711,7 @@ gfc_match_call (void) ...@@ -2711,7 +2711,7 @@ gfc_match_call (void)
{ {
/* ...create a symbol in this scope... */ /* ...create a symbol in this scope... */
if (sym->ns != gfc_current_ns if (sym->ns != gfc_current_ns
&& gfc_get_sym_tree (name, NULL, &st) == 1) && gfc_get_sym_tree (name, NULL, &st, false) == 1)
return MATCH_ERROR; return MATCH_ERROR;
if (sym != st->n.sym) if (sym != st->n.sym)
......
...@@ -160,6 +160,7 @@ void gfc_set_constant_character_len (int, gfc_expr *, int); ...@@ -160,6 +160,7 @@ void gfc_set_constant_character_len (int, gfc_expr *, int);
match gfc_match_allocatable (void); match gfc_match_allocatable (void);
match gfc_match_dimension (void); match gfc_match_dimension (void);
match gfc_match_external (void); match gfc_match_external (void);
match gfc_match_gcc_attributes (void);
match gfc_match_import (void); match gfc_match_import (void);
match gfc_match_intent (void); match gfc_match_intent (void);
match gfc_match_intrinsic (void); match gfc_match_intrinsic (void);
......
...@@ -5006,7 +5006,8 @@ import_iso_c_binding_module (void) ...@@ -5006,7 +5006,8 @@ import_iso_c_binding_module (void)
if (mod_symtree == NULL) if (mod_symtree == NULL)
{ {
/* symtree doesn't already exist in current namespace. */ /* symtree doesn't already exist in current namespace. */
gfc_get_sym_tree (iso_c_module_name, gfc_current_ns, &mod_symtree); gfc_get_sym_tree (iso_c_module_name, gfc_current_ns, &mod_symtree,
false);
if (mod_symtree != NULL) if (mod_symtree != NULL)
mod_sym = mod_symtree->n.sym; mod_sym = mod_symtree->n.sym;
...@@ -5094,7 +5095,7 @@ create_int_parameter (const char *name, int value, const char *modname, ...@@ -5094,7 +5095,7 @@ create_int_parameter (const char *name, int value, const char *modname,
gfc_error ("Symbol '%s' already declared", name); gfc_error ("Symbol '%s' already declared", name);
} }
gfc_get_sym_tree (name, gfc_current_ns, &tmp_symtree); gfc_get_sym_tree (name, gfc_current_ns, &tmp_symtree, false);
sym = tmp_symtree->n.sym; sym = tmp_symtree->n.sym;
sym->module = gfc_get_string (modname); sym->module = gfc_get_string (modname);
...@@ -5135,7 +5136,7 @@ use_iso_fortran_env_module (void) ...@@ -5135,7 +5136,7 @@ use_iso_fortran_env_module (void)
mod_symtree = gfc_find_symtree (gfc_current_ns->sym_root, mod); mod_symtree = gfc_find_symtree (gfc_current_ns->sym_root, mod);
if (mod_symtree == NULL) if (mod_symtree == NULL)
{ {
gfc_get_sym_tree (mod, gfc_current_ns, &mod_symtree); gfc_get_sym_tree (mod, gfc_current_ns, &mod_symtree, false);
gcc_assert (mod_symtree); gcc_assert (mod_symtree);
mod_sym = mod_symtree->n.sym; mod_sym = mod_symtree->n.sym;
......
...@@ -566,6 +566,34 @@ decode_omp_directive (void) ...@@ -566,6 +566,34 @@ decode_omp_directive (void)
return ST_NONE; return ST_NONE;
} }
static gfc_statement
decode_gcc_attribute (void)
{
locus old_locus;
#ifdef GFC_DEBUG
gfc_symbol_state ();
#endif
gfc_clear_error (); /* Clear any pending errors. */
gfc_clear_warning (); /* Clear any pending warnings. */
old_locus = gfc_current_locus;
match ("attributes", gfc_match_gcc_attributes, ST_ATTR_DECL);
/* All else has failed, so give up. See if any of the matchers has
stored an error message of some sort. */
if (gfc_error_check () == 0)
gfc_error_now ("Unclassifiable GCC directive at %C");
reject_statement ();
gfc_error_recovery ();
return ST_NONE;
}
#undef match #undef match
...@@ -637,21 +665,39 @@ next_free (void) ...@@ -637,21 +665,39 @@ next_free (void)
else if (c == '!') else if (c == '!')
{ {
/* Comments have already been skipped by the time we get here, /* Comments have already been skipped by the time we get here,
except for OpenMP directives. */ except for GCC attributes and OpenMP directives. */
if (gfc_option.flag_openmp)
gfc_next_ascii_char (); /* Eat up the exclamation sign. */
c = gfc_peek_ascii_char ();
if (c == 'g')
{ {
int i; int i;
c = gfc_next_ascii_char (); c = gfc_next_ascii_char ();
for (i = 0; i < 5; i++, c = gfc_next_ascii_char ()) for (i = 0; i < 4; i++, c = gfc_next_ascii_char ())
gcc_assert (c == "!$omp"[i]); gcc_assert (c == "gcc$"[i]);
gfc_gobble_whitespace ();
return decode_gcc_attribute ();
}
else if (c == '$' && gfc_option.flag_openmp)
{
int i;
c = gfc_next_ascii_char ();
for (i = 0; i < 4; i++, c = gfc_next_ascii_char ())
gcc_assert (c == "$omp"[i]);
gcc_assert (c == ' ' || c == '\t'); gcc_assert (c == ' ' || c == '\t');
gfc_gobble_whitespace (); gfc_gobble_whitespace ();
return decode_omp_directive (); return decode_omp_directive ();
} }
}
gcc_unreachable ();
}
if (at_bol && c == ';') if (at_bol && c == ';')
{ {
gfc_error_now ("Semicolon at %C needs to be preceded by statement"); gfc_error_now ("Semicolon at %C needs to be preceded by statement");
...@@ -709,12 +755,22 @@ next_fixed (void) ...@@ -709,12 +755,22 @@ next_fixed (void)
break; break;
/* Comments have already been skipped by the time we get /* Comments have already been skipped by the time we get
here, except for OpenMP directives. */ here, except for GCC attributes and OpenMP directives. */
case '*': case '*':
if (gfc_option.flag_openmp) c = gfc_next_char_literal (0);
if (TOLOWER (c) == 'g')
{
for (i = 0; i < 4; i++, c = gfc_next_char_literal (0))
gcc_assert (TOLOWER (c) == "gcc$"[i]);
return decode_gcc_attribute ();
}
else if (c == '$' && gfc_option.flag_openmp)
{ {
for (i = 0; i < 5; i++, c = gfc_next_char_literal (0)) for (i = 0; i < 4; i++, c = gfc_next_char_literal (0))
gcc_assert ((char) gfc_wide_tolower (c) == "*$omp"[i]); gcc_assert ((char) gfc_wide_tolower (c) == "$omp"[i]);
if (c != ' ' && c != '0') if (c != ' ' && c != '0')
{ {
......
...@@ -1388,7 +1388,7 @@ match_actual_arg (gfc_expr **result) ...@@ -1388,7 +1388,7 @@ match_actual_arg (gfc_expr **result)
have a function argument. */ have a function argument. */
if (symtree == NULL) if (symtree == NULL)
{ {
gfc_get_sym_tree (name, NULL, &symtree); gfc_get_sym_tree (name, NULL, &symtree, false);
gfc_set_sym_referenced (symtree->n.sym); gfc_set_sym_referenced (symtree->n.sym);
} }
else else
...@@ -2365,7 +2365,7 @@ check_for_implicit_index (gfc_symtree **st, gfc_symbol **sym) ...@@ -2365,7 +2365,7 @@ check_for_implicit_index (gfc_symtree **st, gfc_symbol **sym)
&& !(*sym)->attr.use_assoc) && !(*sym)->attr.use_assoc)
{ {
int i; int i;
i = gfc_get_sym_tree ((*sym)->name, NULL, st); i = gfc_get_sym_tree ((*sym)->name, NULL, st, false);
if (i) if (i)
return MATCH_ERROR; return MATCH_ERROR;
*sym = (*st)->n.sym; *sym = (*st)->n.sym;
...@@ -2423,7 +2423,7 @@ gfc_match_rvalue (gfc_expr **result) ...@@ -2423,7 +2423,7 @@ gfc_match_rvalue (gfc_expr **result)
if (gfc_find_state (COMP_INTERFACE) == SUCCESS if (gfc_find_state (COMP_INTERFACE) == SUCCESS
&& !gfc_current_ns->has_import_set) && !gfc_current_ns->has_import_set)
i = gfc_get_sym_tree (name, NULL, &symtree); i = gfc_get_sym_tree (name, NULL, &symtree, false);
else else
i = gfc_get_ha_sym_tree (name, &symtree); i = gfc_get_ha_sym_tree (name, &symtree);
...@@ -2782,7 +2782,7 @@ gfc_match_rvalue (gfc_expr **result) ...@@ -2782,7 +2782,7 @@ gfc_match_rvalue (gfc_expr **result)
/* Give up, assume we have a function. */ /* Give up, assume we have a function. */
gfc_get_sym_tree (name, NULL, &symtree); /* Can't fail */ gfc_get_sym_tree (name, NULL, &symtree, false); /* Can't fail */
sym = symtree->n.sym; sym = symtree->n.sym;
e->expr_type = EXPR_FUNCTION; e->expr_type = EXPR_FUNCTION;
...@@ -2815,7 +2815,7 @@ gfc_match_rvalue (gfc_expr **result) ...@@ -2815,7 +2815,7 @@ gfc_match_rvalue (gfc_expr **result)
break; break;
generic_function: generic_function:
gfc_get_sym_tree (name, NULL, &symtree); /* Can't fail */ gfc_get_sym_tree (name, NULL, &symtree, false); /* Can't fail */
e = gfc_get_expr (); e = gfc_get_expr ();
e->symtree = symtree; e->symtree = symtree;
......
...@@ -4400,7 +4400,7 @@ check_host_association (gfc_expr *e) ...@@ -4400,7 +4400,7 @@ check_host_association (gfc_expr *e)
} }
/* Give the symbol a symtree in the right place! */ /* Give the symbol a symtree in the right place! */
gfc_get_sym_tree (sym->name, gfc_current_ns, &st); gfc_get_sym_tree (sym->name, gfc_current_ns, &st, false);
st->n.sym = sym; st->n.sym = sym;
if (old_sym->attr.flavor == FL_PROCEDURE) if (old_sym->attr.flavor == FL_PROCEDURE)
......
...@@ -63,9 +63,10 @@ static gfc_directorylist *include_dirs, *intrinsic_modules_dirs; ...@@ -63,9 +63,10 @@ static gfc_directorylist *include_dirs, *intrinsic_modules_dirs;
static gfc_file *file_head, *current_file; static gfc_file *file_head, *current_file;
static int continue_flag, end_flag, openmp_flag; static int continue_flag, end_flag, openmp_flag, gcc_attribute_flag;
static int continue_count, continue_line; static int continue_count, continue_line;
static locus openmp_locus; static locus openmp_locus;
static locus gcc_attribute_locus;
gfc_source_form gfc_current_form; gfc_source_form gfc_current_form;
static gfc_linebuf *line_head, *line_tail; static gfc_linebuf *line_head, *line_tail;
...@@ -663,6 +664,34 @@ gfc_define_undef_line (void) ...@@ -663,6 +664,34 @@ gfc_define_undef_line (void)
} }
/* Return true if GCC$ was matched. */
static bool
skip_gcc_attribute (locus start)
{
bool r = false;
char c;
locus old_loc = gfc_current_locus;
if ((c = next_char ()) == 'g' || c == 'G')
if ((c = next_char ()) == 'c' || c == 'C')
if ((c = next_char ()) == 'c' || c == 'C')
if ((c = next_char ()) == '$')
r = true;
if (r == false)
gfc_current_locus = old_loc;
else
{
gcc_attribute_flag = 1;
gcc_attribute_locus = old_loc;
gfc_current_locus = start;
}
return r;
}
/* Comment lines are null lines, lines containing only blanks or lines /* Comment lines are null lines, lines containing only blanks or lines
on which the first nonblank line is a '!'. on which the first nonblank line is a '!'.
Return true if !$ openmp conditional compilation sentinel was Return true if !$ openmp conditional compilation sentinel was
...@@ -694,6 +723,10 @@ skip_free_comments (void) ...@@ -694,6 +723,10 @@ skip_free_comments (void)
if (c == '!') if (c == '!')
{ {
/* Keep the !GCC$ line. */
if (at_bol && skip_gcc_attribute (start))
return false;
/* If -fopenmp, we need to handle here 2 things: /* If -fopenmp, we need to handle here 2 things:
1) don't treat !$omp as comments, but directives 1) don't treat !$omp as comments, but directives
2) handle OpenMP conditional compilation, where 2) handle OpenMP conditional compilation, where
...@@ -752,6 +785,8 @@ skip_free_comments (void) ...@@ -752,6 +785,8 @@ skip_free_comments (void)
if (openmp_flag && at_bol) if (openmp_flag && at_bol)
openmp_flag = 0; openmp_flag = 0;
gcc_attribute_flag = 0;
gfc_current_locus = start; gfc_current_locus = start;
return false; return false;
} }
...@@ -806,6 +841,13 @@ skip_fixed_comments (void) ...@@ -806,6 +841,13 @@ skip_fixed_comments (void)
if (c == '!' || c == 'c' || c == 'C' || c == '*') if (c == '!' || c == 'c' || c == 'C' || c == '*')
{ {
if (skip_gcc_attribute (start))
{
/* Canonicalize to *$omp. */
*start.nextc = '*';
return;
}
/* If -fopenmp, we need to handle here 2 things: /* If -fopenmp, we need to handle here 2 things:
1) don't treat !$omp|c$omp|*$omp as comments, but directives 1) don't treat !$omp|c$omp|*$omp as comments, but directives
2) handle OpenMP conditional compilation, where 2) handle OpenMP conditional compilation, where
...@@ -917,6 +959,7 @@ skip_fixed_comments (void) ...@@ -917,6 +959,7 @@ skip_fixed_comments (void)
} }
openmp_flag = 0; openmp_flag = 0;
gcc_attribute_flag = 0;
gfc_current_locus = start; gfc_current_locus = start;
} }
...@@ -963,6 +1006,11 @@ restart: ...@@ -963,6 +1006,11 @@ restart:
if (!in_string && c == '!') if (!in_string && c == '!')
{ {
if (gcc_attribute_flag
&& memcmp (&gfc_current_locus, &gcc_attribute_locus,
sizeof (gfc_current_locus)) == 0)
goto done;
if (openmp_flag if (openmp_flag
&& memcmp (&gfc_current_locus, &openmp_locus, && memcmp (&gfc_current_locus, &openmp_locus,
sizeof (gfc_current_locus)) == 0) sizeof (gfc_current_locus)) == 0)
......
...@@ -809,19 +809,28 @@ duplicate_attr (const char *attr, locus *where) ...@@ -809,19 +809,28 @@ duplicate_attr (const char *attr, locus *where)
} }
gfc_try
gfc_add_ext_attribute (symbol_attribute *attr, unsigned ext_attr,
locus *where ATTRIBUTE_UNUSED)
{
attr->ext_attr |= 1 << ext_attr;
return SUCCESS;
}
/* Called from decl.c (attr_decl1) to check attributes, when declared /* Called from decl.c (attr_decl1) to check attributes, when declared
separately. */ separately. */
gfc_try gfc_try
gfc_add_attribute (symbol_attribute *attr, locus *where) gfc_add_attribute (symbol_attribute *attr, locus *where)
{ {
if (check_used (attr, NULL, where)) if (check_used (attr, NULL, where))
return FAILURE; return FAILURE;
return check_conflict (attr, NULL, where); return check_conflict (attr, NULL, where);
} }
gfc_try gfc_try
gfc_add_allocatable (symbol_attribute *attr, locus *where) gfc_add_allocatable (symbol_attribute *attr, locus *where)
{ {
...@@ -2539,7 +2548,8 @@ save_symbol_data (gfc_symbol *sym) ...@@ -2539,7 +2548,8 @@ save_symbol_data (gfc_symbol *sym)
So if the return value is nonzero, then an error was issued. */ So if the return value is nonzero, then an error was issued. */
int int
gfc_get_sym_tree (const char *name, gfc_namespace *ns, gfc_symtree **result) gfc_get_sym_tree (const char *name, gfc_namespace *ns, gfc_symtree **result,
bool allow_subroutine)
{ {
gfc_symtree *st; gfc_symtree *st;
gfc_symbol *p; gfc_symbol *p;
...@@ -2580,11 +2590,10 @@ gfc_get_sym_tree (const char *name, gfc_namespace *ns, gfc_symtree **result) ...@@ -2580,11 +2590,10 @@ gfc_get_sym_tree (const char *name, gfc_namespace *ns, gfc_symtree **result)
} }
p = st->n.sym; p = st->n.sym;
if (p->ns != ns && (!p->attr.function || ns->proc_name != p) if (p->ns != ns && (!p->attr.function || ns->proc_name != p)
&& !(ns->proc_name && !(allow_subroutine && p->attr.subroutine)
&& ns->proc_name->attr.if_source == IFSRC_IFBODY && !(ns->proc_name && ns->proc_name->attr.if_source == IFSRC_IFBODY
&& (ns->has_import_set || p->attr.imported))) && (ns->has_import_set || p->attr.imported)))
{ {
/* Symbol is from another namespace. */ /* Symbol is from another namespace. */
gfc_error ("Symbol '%s' at %C has already been host associated", gfc_error ("Symbol '%s' at %C has already been host associated",
...@@ -2609,7 +2618,7 @@ gfc_get_symbol (const char *name, gfc_namespace *ns, gfc_symbol **result) ...@@ -2609,7 +2618,7 @@ gfc_get_symbol (const char *name, gfc_namespace *ns, gfc_symbol **result)
gfc_symtree *st; gfc_symtree *st;
int i; int i;
i = gfc_get_sym_tree (name, ns, &st); i = gfc_get_sym_tree (name, ns, &st, false);
if (i != 0) if (i != 0)
return i; return i;
...@@ -2651,7 +2660,7 @@ gfc_get_ha_sym_tree (const char *name, gfc_symtree **result) ...@@ -2651,7 +2660,7 @@ gfc_get_ha_sym_tree (const char *name, gfc_symtree **result)
} }
} }
return gfc_get_sym_tree (name, gfc_current_ns, result); return gfc_get_sym_tree (name, gfc_current_ns, result, false);
} }
...@@ -3653,7 +3662,7 @@ gen_cptr_param (gfc_formal_arglist **head, ...@@ -3653,7 +3662,7 @@ gen_cptr_param (gfc_formal_arglist **head,
c_ptr_in = "gfc_cptr__"; c_ptr_in = "gfc_cptr__";
else else
c_ptr_in = c_ptr_name; c_ptr_in = c_ptr_name;
gfc_get_sym_tree (c_ptr_in, ns, &param_symtree); gfc_get_sym_tree (c_ptr_in, ns, &param_symtree, false);
if (param_symtree != NULL) if (param_symtree != NULL)
param_sym = param_symtree->n.sym; param_sym = param_symtree->n.sym;
else else
...@@ -3719,7 +3728,7 @@ gen_fptr_param (gfc_formal_arglist **head, ...@@ -3719,7 +3728,7 @@ gen_fptr_param (gfc_formal_arglist **head,
if (f_ptr_name != NULL) if (f_ptr_name != NULL)
f_ptr_out = f_ptr_name; f_ptr_out = f_ptr_name;
gfc_get_sym_tree (f_ptr_out, ns, &param_symtree); gfc_get_sym_tree (f_ptr_out, ns, &param_symtree, false);
if (param_symtree != NULL) if (param_symtree != NULL)
param_sym = param_symtree->n.sym; param_sym = param_symtree->n.sym;
else else
...@@ -3766,7 +3775,7 @@ gen_shape_param (gfc_formal_arglist **head, ...@@ -3766,7 +3775,7 @@ gen_shape_param (gfc_formal_arglist **head,
if (shape_param_name != NULL) if (shape_param_name != NULL)
shape_param = shape_param_name; shape_param = shape_param_name;
gfc_get_sym_tree (shape_param, ns, &param_symtree); gfc_get_sym_tree (shape_param, ns, &param_symtree, false);
if (param_symtree != NULL) if (param_symtree != NULL)
param_sym = param_symtree->n.sym; param_sym = param_symtree->n.sym;
else else
...@@ -4115,7 +4124,7 @@ generate_isocbinding_symbol (const char *mod_name, iso_c_binding_symbol s, ...@@ -4115,7 +4124,7 @@ generate_isocbinding_symbol (const char *mod_name, iso_c_binding_symbol s,
return; return;
/* Create the sym tree in the current ns. */ /* Create the sym tree in the current ns. */
gfc_get_sym_tree (name, gfc_current_ns, &tmp_symtree); gfc_get_sym_tree (name, gfc_current_ns, &tmp_symtree, false);
if (tmp_symtree) if (tmp_symtree)
tmp_sym = tmp_symtree->n.sym; tmp_sym = tmp_symtree->n.sym;
else else
......
...@@ -980,6 +980,26 @@ gfc_add_assign_aux_vars (gfc_symbol * sym) ...@@ -980,6 +980,26 @@ gfc_add_assign_aux_vars (gfc_symbol * sym)
GFC_DECL_ASSIGN_ADDR (decl) = addr; GFC_DECL_ASSIGN_ADDR (decl) = addr;
} }
static tree
add_attributes_to_decl (symbol_attribute sym_attr, tree list)
{
unsigned id;
tree attr;
for (id = 0; id < EXT_ATTR_NUM; id++)
if (sym_attr.ext_attr & (1 << id))
{
attr = build_tree_list (
get_identifier (ext_attr_list[id].middle_end_name),
NULL_TREE);
list = chainon (list, attr);
}
return list;
}
/* Return the decl for a gfc_symbol, create it if it doesn't already /* Return the decl for a gfc_symbol, create it if it doesn't already
exist. */ exist. */
...@@ -988,6 +1008,7 @@ gfc_get_symbol_decl (gfc_symbol * sym) ...@@ -988,6 +1008,7 @@ gfc_get_symbol_decl (gfc_symbol * sym)
{ {
tree decl; tree decl;
tree length = NULL_TREE; tree length = NULL_TREE;
tree attributes;
int byref; int byref;
gcc_assert (sym->attr.referenced gcc_assert (sym->attr.referenced
...@@ -1187,6 +1208,10 @@ gfc_get_symbol_decl (gfc_symbol * sym) ...@@ -1187,6 +1208,10 @@ gfc_get_symbol_decl (gfc_symbol * sym)
&& !sym->attr.proc_pointer) && !sym->attr.proc_pointer)
DECL_BY_REFERENCE (decl) = 1; DECL_BY_REFERENCE (decl) = 1;
/* Add attributes to variables. Functions are handled elsewhere. */
attributes = add_attributes_to_decl (sym->attr, NULL_TREE);
decl_attributes (&decl, attributes, 0);
return decl; return decl;
} }
...@@ -1223,6 +1248,7 @@ static tree ...@@ -1223,6 +1248,7 @@ static tree
get_proc_pointer_decl (gfc_symbol *sym) get_proc_pointer_decl (gfc_symbol *sym)
{ {
tree decl; tree decl;
tree attributes;
decl = sym->backend_decl; decl = sym->backend_decl;
if (decl) if (decl)
...@@ -1266,6 +1292,9 @@ get_proc_pointer_decl (gfc_symbol *sym) ...@@ -1266,6 +1292,9 @@ get_proc_pointer_decl (gfc_symbol *sym)
TREE_TYPE (decl), sym->attr.dimension, sym->attr.proc_pointer); TREE_TYPE (decl), sym->attr.dimension, sym->attr.proc_pointer);
} }
attributes = add_attributes_to_decl (sym->attr, NULL_TREE);
decl_attributes (&decl, attributes, 0);
return decl; return decl;
} }
...@@ -1277,6 +1306,7 @@ gfc_get_extern_function_decl (gfc_symbol * sym) ...@@ -1277,6 +1306,7 @@ gfc_get_extern_function_decl (gfc_symbol * sym)
{ {
tree type; tree type;
tree fndecl; tree fndecl;
tree attributes;
gfc_expr e; gfc_expr e;
gfc_intrinsic_sym *isym; gfc_intrinsic_sym *isym;
gfc_expr argexpr; gfc_expr argexpr;
...@@ -1439,6 +1469,9 @@ gfc_get_extern_function_decl (gfc_symbol * sym) ...@@ -1439,6 +1469,9 @@ gfc_get_extern_function_decl (gfc_symbol * sym)
if (DECL_CONTEXT (fndecl) == NULL_TREE) if (DECL_CONTEXT (fndecl) == NULL_TREE)
pushdecl_top_level (fndecl); pushdecl_top_level (fndecl);
attributes = add_attributes_to_decl (sym->attr, NULL_TREE);
decl_attributes (&fndecl, attributes, 0);
return fndecl; return fndecl;
} }
...@@ -1450,7 +1483,7 @@ gfc_get_extern_function_decl (gfc_symbol * sym) ...@@ -1450,7 +1483,7 @@ gfc_get_extern_function_decl (gfc_symbol * sym)
static void static void
build_function_decl (gfc_symbol * sym) build_function_decl (gfc_symbol * sym)
{ {
tree fndecl, type; tree fndecl, type, attributes;
symbol_attribute attr; symbol_attribute attr;
tree result_decl; tree result_decl;
gfc_formal_arglist *f; gfc_formal_arglist *f;
...@@ -1557,6 +1590,9 @@ build_function_decl (gfc_symbol * sym) ...@@ -1557,6 +1590,9 @@ build_function_decl (gfc_symbol * sym)
TREE_SIDE_EFFECTS (fndecl) = 0; TREE_SIDE_EFFECTS (fndecl) = 0;
} }
attributes = add_attributes_to_decl (attr, NULL_TREE);
decl_attributes (&fndecl, attributes, 0);
/* Layout the function declaration and put it in the binding level /* Layout the function declaration and put it in the binding level
of the current function. */ of the current function. */
pushdecl (fndecl); pushdecl (fndecl);
......
2009-06-28 Tobias Burnus <burnus@net-b.de>
PR fortran/34112
* gfortran.dg/compiler-directive_1.f90: New test.
* gfortran.dg/compiler-directive_2.f: New test.
2009-06-28 Kaveh R. Ghazi <ghazi@caip.rutgers.edu> 2009-06-28 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
* gfortran.dg/integer_exponentiation_4.f90: Temporarily * gfortran.dg/integer_exponentiation_4.f90: Temporarily
......
! { dg-do compile }
!
! PR fortran/34112
!
! Check for calling convention consitency
! in procedure-pointer assignments.
program test
interface
subroutine sub1()
end subroutine sub1
subroutine sub2()
!GCC$ ATTRIBUTES CDECL :: sub2
end subroutine sub2
subroutine sub3()
!GCC$ ATTRIBUTES STDCALL :: sub3
end subroutine sub3
subroutine sub4()
!GCC$ ATTRIBUTES FASTCALL :: sub4
end subroutine sub4
end interface
!gcc$ attributes cdecl :: cdecl
!gcc$ attributes stdcall :: stdcall
procedure(), pointer :: ptr
procedure(), pointer :: cdecl
procedure(), pointer :: stdcall
procedure(), pointer :: fastcall
!gcc$ attributes fastcall :: fastcall
! Valid:
ptr => sub1
cdecl => sub2
stdcall => sub3
fastcall => sub4
! Invalid:
ptr => sub3 ! { dg-error "mismatch in the calling convention" }
ptr => sub4 ! { dg-error "mismatch in the calling convention" }
cdecl => sub3 ! { dg-error "mismatch in the calling convention" }
cdecl => sub4 ! { dg-error "mismatch in the calling convention" }
stdcall => sub1 ! { dg-error "mismatch in the calling convention" }
stdcall => sub2 ! { dg-error "mismatch in the calling convention" }
stdcall => sub4 ! { dg-error "mismatch in the calling convention" }
fastcall => sub1 ! { dg-error "mismatch in the calling convention" }
fastcall => sub2 ! { dg-error "mismatch in the calling convention" }
fastcall => sub3 ! { dg-error "mismatch in the calling convention" }
end program
! { dg-do compile { target i?86-*-* x86_64-*-* } }
! { dg-require-effective-target ilp32 }
!
! PR fortran/34112
!
! Check for calling convention consitency
! in procedure-pointer assignments.
!
subroutine test() ! { dg-error "fastcall and stdcall attributes are not compatible" }
cGCC$ attributes stdcall, fastcall::test
end subroutine test
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment