609 lines
20 KiB
Diff
609 lines
20 KiB
Diff
|
2007-08-31 Jakub Jelinek <jakub@redhat.com>
|
||
|
|
||
|
* cp-tree.h (cp_disregard_inline_limits): New prototype.
|
||
|
* decl.c (cp_disregard_inline_limits): New function.
|
||
|
* cp-objcp-common.h
|
||
|
(LANG_HOOKS_TREE_INLINING_DISREGARD_INLINE_LIMITS): Define.
|
||
|
|
||
|
2007-08-30 Jakub Jelinek <jakub@redhat.com>
|
||
|
|
||
|
* gcc.dg/inline-24.c: New test.
|
||
|
* g++.dg/opt/inline11.C: New test.
|
||
|
|
||
|
2007-08-27 Alexandre Oliva <aoliva@redhat.com>
|
||
|
|
||
|
* doc/extend.texi (gnu_inline funtion attribute): Document C++
|
||
|
behavior.
|
||
|
|
||
|
* 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.
|
||
|
|
||
|
* 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.
|
||
|
|
||
|
--- gcc/cp/cp-tree.h.jj 2007-08-31 09:47:43.000000000 +0200
|
||
|
+++ gcc/cp/cp-tree.h 2007-08-31 14:09:08.000000000 +0200
|
||
|
@@ -4417,6 +4417,7 @@ extern linkage_kind decl_linkage (tree)
|
||
|
extern tree cp_walk_subtrees (tree*, int*, walk_tree_fn,
|
||
|
void*, struct pointer_set_t*);
|
||
|
extern int cp_cannot_inline_tree_fn (tree*);
|
||
|
+extern int cp_disregard_inline_limits (tree);
|
||
|
extern tree cp_add_pending_fn_decls (void*,tree);
|
||
|
extern int cp_auto_var_in_fn_p (tree,tree);
|
||
|
extern tree fold_if_not_in_template (tree);
|
||
|
--- gcc/cp/decl.c.jj 2007-08-31 09:47:43.000000000 +0200
|
||
|
+++ gcc/cp/decl.c 2007-08-31 14:27:12.000000000 +0200
|
||
|
@@ -1097,6 +1097,10 @@ check_redeclaration_exception_specificat
|
||
|
}
|
||
|
}
|
||
|
|
||
|
+#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.
|
||
|
@@ -1626,19 +1630,45 @@ duplicate_decls (tree newdecl, tree oldd
|
||
|
= 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. */
|
||
|
- 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)
|
||
|
@@ -1795,9 +1825,29 @@ duplicate_decls (tree newdecl, tree oldd
|
||
|
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_NOT_REALLY_EXTERN (newdecl) |= DECL_NOT_REALLY_EXTERN (olddecl);
|
||
|
+ DECL_COMDAT (newdecl) |= DECL_COMDAT (olddecl);
|
||
|
+ }
|
||
|
DECL_TEMPLATE_INSTANTIATED (newdecl)
|
||
|
|= DECL_TEMPLATE_INSTANTIATED (olddecl);
|
||
|
|
||
|
@@ -1871,6 +1921,13 @@ duplicate_decls (tree newdecl, tree oldd
|
||
|
/* [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)
|
||
|
@@ -2113,9 +2170,25 @@ redeclaration_error_message (tree newdec
|
||
|
{
|
||
|
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 0;
|
||
|
}
|
||
|
else if (TREE_CODE (newdecl) == TEMPLATE_DECL)
|
||
|
@@ -2141,9 +2214,24 @@ redeclaration_error_message (tree newdec
|
||
|
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";
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
return NULL;
|
||
|
}
|
||
|
else if (TREE_CODE (newdecl) == VAR_DECL
|
||
|
@@ -10447,6 +10535,14 @@ start_preparsed_function (tree decl1, tr
|
||
|
&& 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
|
||
|
@@ -10702,8 +10798,9 @@ start_preparsed_function (tree decl1, tr
|
||
|
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))
|
||
|
@@ -11698,4 +11795,17 @@ cxx_comdat_group (tree decl)
|
||
|
return IDENTIFIER_POINTER (name);
|
||
|
}
|
||
|
|
||
|
+/* We want to inline __gnu_inline__ functions even if this would
|
||
|
+ violate inlining limits. Some glibc and linux constructs depend on
|
||
|
+ such functions always being inlined when optimizing. */
|
||
|
+
|
||
|
+int
|
||
|
+cp_disregard_inline_limits (tree fn)
|
||
|
+{
|
||
|
+ if (lookup_attribute ("always_inline", DECL_ATTRIBUTES (fn)) != NULL)
|
||
|
+ return 1;
|
||
|
+
|
||
|
+ return (!flag_really_no_inline && GNU_INLINE_P (fn));
|
||
|
+}
|
||
|
+
|
||
|
#include "gt-cp-decl.h"
|
||
|
--- gcc/cp/cp-objcp-common.h.jj 2007-02-20 22:37:34.000000000 +0100
|
||
|
+++ gcc/cp/cp-objcp-common.h 2007-08-31 13:58:32.000000000 +0200
|
||
|
@@ -107,6 +107,9 @@ extern tree objcp_tsubst_copy_and_build
|
||
|
#undef LANG_HOOKS_TREE_INLINING_CANNOT_INLINE_TREE_FN
|
||
|
#define LANG_HOOKS_TREE_INLINING_CANNOT_INLINE_TREE_FN \
|
||
|
cp_cannot_inline_tree_fn
|
||
|
+#undef LANG_HOOKS_TREE_INLINING_DISREGARD_INLINE_LIMITS
|
||
|
+#define LANG_HOOKS_TREE_INLINING_DISREGARD_INLINE_LIMITS \
|
||
|
+ cp_disregard_inline_limits
|
||
|
#undef LANG_HOOKS_TREE_INLINING_ADD_PENDING_FN_DECLS
|
||
|
#define LANG_HOOKS_TREE_INLINING_ADD_PENDING_FN_DECLS \
|
||
|
cp_add_pending_fn_decls
|
||
|
--- gcc/doc/extend.texi.jj 2007-08-31 09:47:40.000000000 +0200
|
||
|
+++ gcc/doc/extend.texi 2007-08-31 13:00:28.000000000 +0200
|
||
|
@@ -1587,8 +1587,8 @@ refer to the single copy in the library.
|
||
|
definitions of the functions need not be precisely the same, although
|
||
|
if they do not have the same effect your program may behave oddly.
|
||
|
|
||
|
-If the function is neither @code{extern} nor @code{static}, then the
|
||
|
-function is compiled as a standalone function, as well as being
|
||
|
+In C, if the function is neither @code{extern} nor @code{static}, then
|
||
|
+the function is compiled as a standalone function, as well as being
|
||
|
inlined where possible.
|
||
|
|
||
|
This is how GCC traditionally handled functions declared
|
||
|
@@ -1606,6 +1606,10 @@ assume that it is always present, whethe
|
||
|
In versions prior to 4.3, the only effect of explicitly including it is
|
||
|
to disable warnings about using inline functions in C99 mode.
|
||
|
|
||
|
+In C++, this attribute does not depend on @code{extern} in any way,
|
||
|
+but it still requires the @code{inline} keyword to enable its special
|
||
|
+behavior.
|
||
|
+
|
||
|
@cindex @code{flatten} function attribute
|
||
|
@item flatten
|
||
|
Generally, inlining into a function is limited. For a function marked with
|
||
|
--- gcc/testsuite/gcc.dg/inline-24.c.jj 2007-08-31 14:11:45.000000000 +0200
|
||
|
+++ gcc/testsuite/gcc.dg/inline-24.c 2007-08-30 18:43:55.000000000 +0200
|
||
|
@@ -0,0 +1,28 @@
|
||
|
+/* Verify that gnu_inline inlines disregard inlining limits. */
|
||
|
+/* { dg-do link } */
|
||
|
+/* { dg-options "-O2" } */
|
||
|
+
|
||
|
+extern int foo (int);
|
||
|
+extern int baz (int);
|
||
|
+
|
||
|
+extern inline __attribute__((gnu_inline))
|
||
|
+int foo (int x)
|
||
|
+{
|
||
|
+ int i;
|
||
|
+ if (!__builtin_constant_p (x))
|
||
|
+ {
|
||
|
+#define B(n) baz (1##n) + baz (2##n) + baz (3##n) \
|
||
|
+ + baz (4##n) + baz (5##n) + baz (6##n)
|
||
|
+#define C(n) B(1##n) + B(2##n) + B(3##n) + B(4##n) + B(5##n) + B(6##n)
|
||
|
+#define D(n) C(1##n) + C(2##n) + C(3##n) + C(4##n) + C(5##n) + C(6##n)
|
||
|
+ return D(0) + D(1) + D(2) + D(3) + D(4)
|
||
|
+ + D(5) + D(6) + D(7) + D(8) + D(9);
|
||
|
+ }
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+int
|
||
|
+main (void)
|
||
|
+{
|
||
|
+ return foo (0);
|
||
|
+}
|
||
|
--- gcc/testsuite/g++.dg/opt/inline11.C.jj 2007-08-31 14:12:05.000000000 +0200
|
||
|
+++ gcc/testsuite/g++.dg/opt/inline11.C 2007-08-30 18:43:55.000000000 +0200
|
||
|
@@ -0,0 +1,28 @@
|
||
|
+/* Verify that gnu_inline inlines disregard inlining limits. */
|
||
|
+/* { dg-do link } */
|
||
|
+/* { dg-options "-O2" } */
|
||
|
+
|
||
|
+extern int foo (int);
|
||
|
+extern int baz (int);
|
||
|
+
|
||
|
+extern inline __attribute__((gnu_inline))
|
||
|
+int foo (int x)
|
||
|
+{
|
||
|
+ int i;
|
||
|
+ if (!__builtin_constant_p (x))
|
||
|
+ {
|
||
|
+#define B(n) baz (1##n) + baz (2##n) + baz (3##n) \
|
||
|
+ + baz (4##n) + baz (5##n) + baz (6##n)
|
||
|
+#define C(n) B(1##n) + B(2##n) + B(3##n) + B(4##n) + B(5##n) + B(6##n)
|
||
|
+#define D(n) C(1##n) + C(2##n) + C(3##n) + C(4##n) + C(5##n) + C(6##n)
|
||
|
+ return D(0) + D(1) + D(2) + D(3) + D(4)
|
||
|
+ + D(5) + D(6) + D(7) + D(8) + D(9);
|
||
|
+ }
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+int
|
||
|
+main (void)
|
||
|
+{
|
||
|
+ return foo (0);
|
||
|
+}
|
||
|
--- gcc/testsuite/g++.dg/ext/gnu-inline-global-reject.C.jj 2007-08-31 13:00:28.000000000 +0200
|
||
|
+++ gcc/testsuite/g++.dg/ext/gnu-inline-global-reject.C 2007-08-31 13:00:28.000000000 +0200
|
||
|
@@ -0,0 +1,55 @@
|
||
|
+/* Test __attribute__((gnu_inline)).
|
||
|
+
|
||
|
+ Check that we reject various forms of duplicate definitions.
|
||
|
+*/
|
||
|
+
|
||
|
+/* { dg-do compile } */
|
||
|
+
|
||
|
+#include "gnu-inline-common.h"
|
||
|
+
|
||
|
+#undef fn
|
||
|
+#define fn pfx(func_decl_inline_before)
|
||
|
+decl(inline, fn) // { dg-error "previous" "" }
|
||
|
+gnuindef(fn, 0) // { dg-error "redeclared" "" }
|
||
|
+
|
||
|
+#undef fn
|
||
|
+#define fn pfx(func_decl_inline_after)
|
||
|
+gnuindef(fn, 0) // { dg-error "previous" "" }
|
||
|
+decl(inline, fn) // { dg-error "redeclared" "" }
|
||
|
+
|
||
|
+#undef fn
|
||
|
+#define fn pfx(func_def_gnuin_redef)
|
||
|
+gnuindef(fn, 0) // { dg-error "previous" "" }
|
||
|
+gnuindef(fn, 1) // { dg-error "redefinition" "" }
|
||
|
+
|
||
|
+#undef fn
|
||
|
+#define fn pfx(func_def_inline_redef)
|
||
|
+def(inline, fn, 0) // { dg-error "previous" "" }
|
||
|
+def(inline, fn, 1) // { dg-error "redefinition" "" }
|
||
|
+
|
||
|
+#undef fn
|
||
|
+#define fn pfx(func_def_inline_after)
|
||
|
+gnuindef(fn, 0) // { dg-error "previous" "" }
|
||
|
+def(inline, fn, 1) // { dg-error "redeclare" "" }
|
||
|
+
|
||
|
+#undef fn
|
||
|
+#define fn pfx(func_def_inline_before)
|
||
|
+def(inline, fn, 0) // { dg-error "previous" "" }
|
||
|
+gnuindef(fn, 1) // { dg-error "redefinition" "" }
|
||
|
+
|
||
|
+#undef fn
|
||
|
+#define fn pfx(func_def_before)
|
||
|
+def(, fn, 0) // { dg-error "previous" "" }
|
||
|
+gnuindef(fn, 1) // { dg-error "redefinition" "" }
|
||
|
+
|
||
|
+#undef fn
|
||
|
+#define fn pfx(func_decl_static_inline_before)
|
||
|
+decl(static inline, fn) // { dg-error "previous" "" }
|
||
|
+gnuindef(fn, 0) // { dg-error "redeclared" "" }
|
||
|
+
|
||
|
+#undef fn
|
||
|
+#define fn pfx(func_def_static_inline_after)
|
||
|
+decl(static, fn)
|
||
|
+gnuindef(fn, 0) // { dg-error "previous" "" }
|
||
|
+decl(static, fn)
|
||
|
+def(static inline, fn, 1) // { dg-error "redeclare" "" }
|
||
|
--- gcc/testsuite/g++.dg/ext/gnu-inline-template-func.C.jj 2007-08-31 13:00:28.000000000 +0200
|
||
|
+++ gcc/testsuite/g++.dg/ext/gnu-inline-template-func.C 2007-08-31 13:00:28.000000000 +0200
|
||
|
@@ -0,0 +1,17 @@
|
||
|
+/* { dg-do compile } */
|
||
|
+/* { dg-options "-O" } */ // such that static functions are optimized out
|
||
|
+/* { dg-final { scan-assembler "func1" } } */
|
||
|
+/* { dg-final { scan-assembler "func2" } } */
|
||
|
+/* { dg-final { scan-assembler-not "func3" } } */
|
||
|
+/* { dg-final { scan-assembler "func4" } } */
|
||
|
+/* { dg-final { scan-assembler-not "func5" } } */
|
||
|
+
|
||
|
+#define defpfx template <typename T>
|
||
|
+
|
||
|
+#include "gnu-inline-global.C"
|
||
|
+
|
||
|
+template int func1<int>(void);
|
||
|
+template int func2<int>(void);
|
||
|
+template int func3<int>(void);
|
||
|
+template int func4<int>(void);
|
||
|
+template int func5<int>(void);
|
||
|
--- gcc/testsuite/g++.dg/ext/gnu-inline-common.h.jj 2007-08-31 13:00:28.000000000 +0200
|
||
|
+++ gcc/testsuite/g++.dg/ext/gnu-inline-common.h 2007-08-31 13:00:28.000000000 +0200
|
||
|
@@ -0,0 +1,24 @@
|
||
|
+#ifndef gnu
|
||
|
+# define gnu_inline __attribute__((gnu_inline)) inline
|
||
|
+#endif
|
||
|
+
|
||
|
+#define declspec(spec, name) spec int name (void)
|
||
|
+#ifdef IN_CLASS
|
||
|
+# define decl(spec, name)
|
||
|
+#else
|
||
|
+# define decl(spec, name) defpfx declspec(spec, name);
|
||
|
+#endif
|
||
|
+#define def(spec, name, ret) defpfx declspec(spec, name) { return ret; }
|
||
|
+#define gnuindef(name, ret) def(gnu_inline, name, ret)
|
||
|
+
|
||
|
+#ifndef pfx
|
||
|
+# ifdef IN_CLASS
|
||
|
+# define pfx(x) IN_CLASS::x
|
||
|
+# else
|
||
|
+# define pfx(x) x
|
||
|
+# endif
|
||
|
+#endif
|
||
|
+
|
||
|
+#ifndef defpfx
|
||
|
+# define defpfx
|
||
|
+#endif
|
||
|
--- gcc/testsuite/g++.dg/ext/gnu-inline-anon-namespace.C.jj 2007-08-31 13:00:28.000000000 +0200
|
||
|
+++ gcc/testsuite/g++.dg/ext/gnu-inline-anon-namespace.C 2007-08-31 13:00:28.000000000 +0200
|
||
|
@@ -0,0 +1,11 @@
|
||
|
+/* { dg-do compile } */
|
||
|
+/* { dg-options "-O" } */ // such that static functions are optimized out
|
||
|
+/* { dg-final { scan-assembler-not "func1" } } */
|
||
|
+/* { dg-final { scan-assembler-not "func2" } } */
|
||
|
+/* { dg-final { scan-assembler-not "func3" } } */
|
||
|
+/* { dg-final { scan-assembler-not "func4" } } */
|
||
|
+/* { dg-final { scan-assembler-not "func5" } } */
|
||
|
+
|
||
|
+namespace {
|
||
|
+#include "gnu-inline-global.C"
|
||
|
+}
|
||
|
--- gcc/testsuite/g++.dg/ext/gnu-inline-class-static.C.jj 2007-08-31 13:00:28.000000000 +0200
|
||
|
+++ gcc/testsuite/g++.dg/ext/gnu-inline-class-static.C 2007-08-31 13:00:28.000000000 +0200
|
||
|
@@ -0,0 +1,20 @@
|
||
|
+/* { dg-do compile } */
|
||
|
+/* { dg-options "-O" } */ // such that static functions are optimized out
|
||
|
+/* { dg-final { scan-assembler "func1" } } */
|
||
|
+/* { dg-final { scan-assembler "func2" } } */
|
||
|
+/* { dg-final { scan-assembler-not "func3" } } */
|
||
|
+/* { dg-final { scan-assembler "func4" } } */
|
||
|
+/* { dg-final { scan-assembler "func5" } } */
|
||
|
+
|
||
|
+#undef IN_CLASS
|
||
|
+#define IN_CLASS gnu_test_static
|
||
|
+
|
||
|
+struct IN_CLASS {
|
||
|
+ static int func1(void);
|
||
|
+ static int func2(void);
|
||
|
+ static int func3(void);
|
||
|
+ static int func4(void);
|
||
|
+ static int func5(void);
|
||
|
+};
|
||
|
+
|
||
|
+#include "gnu-inline-global.C"
|
||
|
--- gcc/testsuite/g++.dg/ext/gnu-inline-global.C.jj 2007-08-31 13:00:28.000000000 +0200
|
||
|
+++ gcc/testsuite/g++.dg/ext/gnu-inline-global.C 2007-08-31 13:00:28.000000000 +0200
|
||
|
@@ -0,0 +1,50 @@
|
||
|
+/* Test __attribute__((gnu_inline)).
|
||
|
+
|
||
|
+ Check that __attribute__((gnu_inline)) has no effect, in the
|
||
|
+ absence of extern and/or inline.
|
||
|
+
|
||
|
+ Check that we don't get out-of-line definitions for extern inline
|
||
|
+ gnu_inline functions, regardless of declarations or definitions.
|
||
|
+
|
||
|
+ Check that such functions can be overridden by out-of-line
|
||
|
+ definitions.
|
||
|
+
|
||
|
+ */
|
||
|
+
|
||
|
+/* { dg-do compile } */
|
||
|
+/* { dg-options "-O" } */ // such that static functions are optimized out
|
||
|
+/* { dg-final { scan-assembler "func1" } } */
|
||
|
+/* { dg-final { scan-assembler "func2" } } */
|
||
|
+/* { dg-final { scan-assembler-not "func3" } } */
|
||
|
+/* { dg-final { scan-assembler "func4" } } */
|
||
|
+/* { dg-final { scan-assembler-not "func5" } } */
|
||
|
+
|
||
|
+#include "gnu-inline-common.h"
|
||
|
+
|
||
|
+#undef fn
|
||
|
+#define fn pfx(func1) // must be emitted out-of-line
|
||
|
+gnuindef(fn, 0)
|
||
|
+def(, fn, 2)
|
||
|
+
|
||
|
+#undef fn
|
||
|
+#define fn pfx(func2) // must be emitted out-of-line
|
||
|
+decl(extern, fn)
|
||
|
+gnuindef(fn, 0)
|
||
|
+def(, fn, 2)
|
||
|
+
|
||
|
+#undef fn
|
||
|
+#define fn pfx(func3) // must not be emitted
|
||
|
+decl(extern, fn)
|
||
|
+gnuindef(fn, 0)
|
||
|
+
|
||
|
+#undef fn
|
||
|
+#define fn pfx(func4) // must be emitted out-of-line
|
||
|
+decl(extern, fn)
|
||
|
+gnuindef(fn, 0)
|
||
|
+def(, fn, 1)
|
||
|
+
|
||
|
+#undef fn
|
||
|
+#define fn pfx(func5) // must NOT be emitted, because it's static and unused
|
||
|
+decl(static, fn)
|
||
|
+gnuindef(fn, 0)
|
||
|
+def(, fn, 1)
|
||
|
--- gcc/testsuite/g++.dg/ext/gnu-inline-template-class.C.jj 2007-08-31 13:00:28.000000000 +0200
|
||
|
+++ gcc/testsuite/g++.dg/ext/gnu-inline-template-class.C 2007-08-31 13:00:28.000000000 +0200
|
||
|
@@ -0,0 +1,22 @@
|
||
|
+/* { dg-do compile } */
|
||
|
+/* { dg-options "-O" } */ // such that static functions are optimized out
|
||
|
+/* { dg-final { scan-assembler "func1" } } */
|
||
|
+/* { dg-final { scan-assembler "func2" } } */
|
||
|
+/* { dg-final { scan-assembler-not "func3" } } */
|
||
|
+/* { dg-final { scan-assembler "func4" } } */
|
||
|
+/* { dg-final { scan-assembler "func5" } } */
|
||
|
+
|
||
|
+template <typename T> struct gnu_test {
|
||
|
+ int func1(void);
|
||
|
+ int func2(void);
|
||
|
+ int func3(void);
|
||
|
+ int func4(void);
|
||
|
+ int func5(void);
|
||
|
+};
|
||
|
+
|
||
|
+#define defpfx template <typename T>
|
||
|
+#define IN_CLASS gnu_test<T>
|
||
|
+
|
||
|
+#include "gnu-inline-global.C"
|
||
|
+
|
||
|
+template struct gnu_test<int>;
|
||
|
--- gcc/testsuite/g++.dg/ext/gnu-inline-namespace.C.jj 2007-08-31 13:00:28.000000000 +0200
|
||
|
+++ gcc/testsuite/g++.dg/ext/gnu-inline-namespace.C 2007-08-31 13:00:28.000000000 +0200
|
||
|
@@ -0,0 +1,11 @@
|
||
|
+/* { dg-do compile } */
|
||
|
+/* { dg-options "-O" } */ // such that static functions are optimized out
|
||
|
+/* { dg-final { scan-assembler "func1" } } */
|
||
|
+/* { dg-final { scan-assembler "func2" } } */
|
||
|
+/* { dg-final { scan-assembler-not "func3" } } */
|
||
|
+/* { dg-final { scan-assembler "func4" } } */
|
||
|
+/* { dg-final { scan-assembler-not "func5" } } */
|
||
|
+
|
||
|
+namespace gnu_test {
|
||
|
+#include "gnu-inline-global.C"
|
||
|
+}
|
||
|
--- gcc/testsuite/g++.dg/ext/gnu-inline-class.C.jj 2007-08-31 13:00:28.000000000 +0200
|
||
|
+++ gcc/testsuite/g++.dg/ext/gnu-inline-class.C 2007-08-31 13:00:28.000000000 +0200
|
||
|
@@ -0,0 +1,19 @@
|
||
|
+/* { dg-do compile } */
|
||
|
+/* { dg-options "-O" } */ // such that static functions are optimized out
|
||
|
+/* { dg-final { scan-assembler "func1" } } */
|
||
|
+/* { dg-final { scan-assembler "func2" } } */
|
||
|
+/* { dg-final { scan-assembler-not "func3" } } */
|
||
|
+/* { dg-final { scan-assembler "func4" } } */
|
||
|
+/* { dg-final { scan-assembler "func5" } } */
|
||
|
+
|
||
|
+#define IN_CLASS gnu_test
|
||
|
+
|
||
|
+struct IN_CLASS {
|
||
|
+ int func1(void);
|
||
|
+ int func2(void);
|
||
|
+ int func3(void);
|
||
|
+ int func4(void);
|
||
|
+ int func5(void);
|
||
|
+};
|
||
|
+
|
||
|
+#include "gnu-inline-global.C"
|