summaryrefslogtreecommitdiff
path: root/gcc/cp
diff options
context:
space:
mode:
authoraoliva <aoliva@138bc75d-0d04-0410-961f-82ee72b054a4>2007-08-27 20:40:00 +0000
committeraoliva <aoliva@138bc75d-0d04-0410-961f-82ee72b054a4>2007-08-27 20:40:00 +0000
commitdb5779008598ad8546bef62ffc8bd2e228f7bc46 (patch)
treef558d774fa8c7f13553e534c150c8c4a1f1c8f25 /gcc/cp
parentcf39ec50a992c196a37ba5486ce6412096e867d0 (diff)
downloadgcc-db5779008598ad8546bef62ffc8bd2e228f7bc46.tar.gz
gcc/ChangeLog:
* doc/extend.texi (gnu_inline funtion attribute): Document C++ behavior. gcc/cp/ChangeLog: * decl.c (GNU_INLINE_P): New. (duplicate_decls): Handle gnu_inline. Merge attributes and some flags in overriding definitions. (redeclaration_error_message): Handle gnu_inline. (start_preparsed_function): Likewise. gcc/testsuite/ChangeLog: * g++.dg/ext/gnu-inline-common.h: New. * g++.dg/ext/gnu-inline-global-reject.C: New. * g++.dg/ext/gnu-inline-global.C: New. * g++.dg/ext/gnu-inline-namespace.C: New. * g++.dg/ext/gnu-inline-anon-namespace.C: New. * g++.dg/ext/gnu-inline-class.C: New. * g++.dg/ext/gnu-inline-class-static.C: New. * g++.dg/ext/gnu-inline-template-class.C: New. * g++.dg/ext/gnu-inline-template-func.C: New. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@127839 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/cp')
-rw-r--r--gcc/cp/ChangeLog8
-rw-r--r--gcc/cp/decl.c126
2 files changed, 120 insertions, 14 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index d073d38e152..ca09bf4ea31 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,11 @@
+2007-08-27 Alexandre Oliva <aoliva@redhat.com>
+
+ * decl.c (GNU_INLINE_P): New.
+ (duplicate_decls): Handle gnu_inline. Merge attributes and
+ some flags in overriding definitions.
+ (redeclaration_error_message): Handle gnu_inline.
+ (start_preparsed_function): Likewise.
+
2007-08-25 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
* call.c (sufficient_parms_p): Constify.
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index f054b662c26..ef63ffd83ac 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -1098,6 +1098,10 @@ check_redeclaration_exception_specification (tree new_decl,
}
}
+#define GNU_INLINE_P(fn) (DECL_DECLARED_INLINE_P (fn) \
+ && lookup_attribute ("gnu_inline", \
+ DECL_ATTRIBUTES (fn)))
+
/* If NEWDECL is a redeclaration of OLDDECL, merge the declarations.
If the redeclaration is invalid, a diagnostic is issued, and the
error_mark_node is returned. Otherwise, OLDDECL is returned.
@@ -1634,20 +1638,46 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
= chainon (DECL_TEMPLATE_SPECIALIZATIONS (olddecl),
DECL_TEMPLATE_SPECIALIZATIONS (newdecl));
+ DECL_ATTRIBUTES (old_result)
+ = (*targetm.merge_decl_attributes) (old_result, new_result);
+
if (DECL_FUNCTION_TEMPLATE_P (newdecl))
{
- DECL_INLINE (old_result)
- |= DECL_INLINE (new_result);
- DECL_DECLARED_INLINE_P (old_result)
- |= DECL_DECLARED_INLINE_P (new_result);
- check_redeclaration_exception_specification (newdecl, olddecl);
+ if (GNU_INLINE_P (old_result) != GNU_INLINE_P (new_result)
+ && DECL_INITIAL (new_result))
+ {
+ if (DECL_INITIAL (old_result))
+ {
+ DECL_INLINE (old_result) = 0;
+ DECL_UNINLINABLE (old_result) = 1;
+ }
+ else
+ {
+ DECL_INLINE (old_result) = DECL_INLINE (new_result);
+ DECL_UNINLINABLE (old_result) = DECL_UNINLINABLE (new_result);
+ }
+ DECL_EXTERNAL (old_result) = DECL_EXTERNAL (new_result);
+ DECL_NOT_REALLY_EXTERN (old_result)
+ = DECL_NOT_REALLY_EXTERN (new_result);
+ DECL_INTERFACE_KNOWN (old_result)
+ = DECL_INTERFACE_KNOWN (new_result);
+ DECL_DECLARED_INLINE_P (old_result)
+ = DECL_DECLARED_INLINE_P (new_result);
+ }
+ else
+ {
+ DECL_INLINE (old_result)
+ |= DECL_INLINE (new_result);
+ DECL_DECLARED_INLINE_P (old_result)
+ |= DECL_DECLARED_INLINE_P (new_result);
+ check_redeclaration_exception_specification (newdecl, olddecl);
+ }
}
/* If the new declaration is a definition, update the file and
line information on the declaration, and also make
the old declaration the same definition. */
- if (DECL_INITIAL (old_result) == NULL_TREE
- && DECL_INITIAL (new_result) != NULL_TREE)
+ if (DECL_INITIAL (new_result) != NULL_TREE)
{
DECL_SOURCE_LOCATION (olddecl)
= DECL_SOURCE_LOCATION (old_result)
@@ -1805,9 +1835,30 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
new_template = NULL_TREE;
if (DECL_LANG_SPECIFIC (newdecl) && DECL_LANG_SPECIFIC (olddecl))
{
- DECL_INTERFACE_KNOWN (newdecl) |= DECL_INTERFACE_KNOWN (olddecl);
- DECL_NOT_REALLY_EXTERN (newdecl) |= DECL_NOT_REALLY_EXTERN (olddecl);
- DECL_COMDAT (newdecl) |= DECL_COMDAT (olddecl);
+ bool old_decl_gnu_inline;
+
+ if ((DECL_INTERFACE_KNOWN (olddecl)
+ && TREE_CODE (olddecl) == FUNCTION_DECL)
+ || (TREE_CODE (olddecl) == TEMPLATE_DECL
+ && TREE_CODE (DECL_TEMPLATE_RESULT (olddecl)) == FUNCTION_DECL))
+ {
+ tree fn = olddecl;
+
+ if (TREE_CODE (fn) == TEMPLATE_DECL)
+ fn = DECL_TEMPLATE_RESULT (olddecl);
+
+ old_decl_gnu_inline = GNU_INLINE_P (fn) && DECL_INITIAL (fn);
+ }
+ else
+ old_decl_gnu_inline = false;
+
+ if (!old_decl_gnu_inline)
+ {
+ DECL_INTERFACE_KNOWN (newdecl) |= DECL_INTERFACE_KNOWN (olddecl);
+ DECL_INTERFACE_KNOWN (newdecl) |= DECL_INTERFACE_KNOWN (olddecl);
+ DECL_NOT_REALLY_EXTERN (newdecl) |= DECL_NOT_REALLY_EXTERN (olddecl);
+ DECL_COMDAT (newdecl) |= DECL_COMDAT (olddecl);
+ }
DECL_TEMPLATE_INSTANTIATED (newdecl)
|= DECL_TEMPLATE_INSTANTIATED (olddecl);
@@ -1881,6 +1932,13 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
/* [temp.expl.spec/14] We don't inline explicit specialization
just because the primary template says so. */
}
+ else if (new_defines_function && DECL_INITIAL (olddecl))
+ {
+ /* C++ is always in in unit-at-a-time mode, so we never
+ inline re-defined extern inline functions. */
+ DECL_INLINE (newdecl) = 0;
+ DECL_UNINLINABLE (newdecl) = 1;
+ }
else
{
if (DECL_PENDING_INLINE_INFO (newdecl) == 0)
@@ -2123,9 +2181,25 @@ redeclaration_error_message (tree newdecl, tree olddecl)
{
if (DECL_NAME (olddecl) == NULL_TREE)
return "%q#D not declared in class";
- else
+ else if (!GNU_INLINE_P (olddecl)
+ || GNU_INLINE_P (newdecl))
return "redefinition of %q#D";
}
+
+ if (DECL_DECLARED_INLINE_P (olddecl) && DECL_DECLARED_INLINE_P (newdecl))
+ {
+ bool olda = GNU_INLINE_P (olddecl);
+ bool newa = GNU_INLINE_P (newdecl);
+
+ if (olda != newa)
+ {
+ if (newa)
+ return "%q+D redeclared inline with %<gnu_inline%> attribute";
+ else
+ return "%q+D redeclared inline without %<gnu_inline%> attribute";
+ }
+ }
+
return NULL;
}
else if (TREE_CODE (newdecl) == TEMPLATE_DECL)
@@ -2151,9 +2225,24 @@ redeclaration_error_message (tree newdecl, tree olddecl)
ot = DECL_TEMPLATE_RESULT (olddecl);
if (DECL_TEMPLATE_INFO (ot))
ot = DECL_TEMPLATE_RESULT (template_for_substitution (ot));
- if (DECL_INITIAL (nt) && DECL_INITIAL (ot))
+ if (DECL_INITIAL (nt) && DECL_INITIAL (ot)
+ && (!GNU_INLINE_P (ot) || GNU_INLINE_P (nt)))
return "redefinition of %q#D";
+ if (DECL_DECLARED_INLINE_P (ot) && DECL_DECLARED_INLINE_P (nt))
+ {
+ bool olda = GNU_INLINE_P (ot);
+ bool newa = GNU_INLINE_P (nt);
+
+ if (olda != newa)
+ {
+ if (newa)
+ return "%q+D redeclared inline with %<gnu_inline%> attribute";
+ else
+ return "%q+D redeclared inline without %<gnu_inline%> attribute";
+ }
+ }
+
/* Core issue #226 (C++0x):
If a friend function template declaration specifies a
@@ -10786,6 +10875,14 @@ start_preparsed_function (tree decl1, tree attrs, int flags)
&& lookup_attribute ("noinline", attrs))
warning (0, "inline function %q+D given attribute noinline", decl1);
+ /* Handle gnu_inline attribute. */
+ if (GNU_INLINE_P (decl1))
+ {
+ DECL_EXTERNAL (decl1) = 1;
+ DECL_NOT_REALLY_EXTERN (decl1) = 0;
+ DECL_INTERFACE_KNOWN (decl1) = 1;
+ }
+
if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (decl1))
/* This is a constructor, we must ensure that any default args
introduced by this definition are propagated to the clones
@@ -11071,8 +11168,9 @@ start_preparsed_function (tree decl1, tree attrs, int flags)
else
{
/* This is a definition, not a reference.
- So clear DECL_EXTERNAL. */
- DECL_EXTERNAL (decl1) = 0;
+ So clear DECL_EXTERNAL, unless this is a GNU extern inline. */
+ if (!GNU_INLINE_P (decl1))
+ DECL_EXTERNAL (decl1) = 0;
if ((DECL_DECLARED_INLINE_P (decl1)
|| DECL_TEMPLATE_INSTANTIATION (decl1))