extend.texi (gnu_inline funtion attribute): Document C++ behavior.
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. From-SVN: r127839
This commit is contained in:
parent
83d7e8f06e
commit
3a47c4e4f4
|
@ -1,3 +1,8 @@
|
||||||
|
2007-08-27 Alexandre Oliva <aoliva@redhat.com>
|
||||||
|
|
||||||
|
* doc/extend.texi (gnu_inline funtion attribute): Document C++
|
||||||
|
behavior.
|
||||||
|
|
||||||
2007-08-27 Jason Merrill <jason@redhat.com>
|
2007-08-27 Jason Merrill <jason@redhat.com>
|
||||||
|
|
||||||
PR c++/31337
|
PR c++/31337
|
||||||
|
|
|
@ -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>
|
2007-08-25 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
|
||||||
|
|
||||||
* call.c (sufficient_parms_p): Constify.
|
* call.c (sufficient_parms_p): Constify.
|
||||||
|
|
108
gcc/cp/decl.c
108
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 NEWDECL is a redeclaration of OLDDECL, merge the declarations.
|
||||||
If the redeclaration is invalid, a diagnostic is issued, and the
|
If the redeclaration is invalid, a diagnostic is issued, and the
|
||||||
error_mark_node is returned. Otherwise, OLDDECL is returned.
|
error_mark_node is returned. Otherwise, OLDDECL is returned.
|
||||||
|
@ -1634,7 +1638,33 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
|
||||||
= chainon (DECL_TEMPLATE_SPECIALIZATIONS (olddecl),
|
= chainon (DECL_TEMPLATE_SPECIALIZATIONS (olddecl),
|
||||||
DECL_TEMPLATE_SPECIALIZATIONS (newdecl));
|
DECL_TEMPLATE_SPECIALIZATIONS (newdecl));
|
||||||
|
|
||||||
|
DECL_ATTRIBUTES (old_result)
|
||||||
|
= (*targetm.merge_decl_attributes) (old_result, new_result);
|
||||||
|
|
||||||
if (DECL_FUNCTION_TEMPLATE_P (newdecl))
|
if (DECL_FUNCTION_TEMPLATE_P (newdecl))
|
||||||
|
{
|
||||||
|
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 (old_result)
|
||||||
|= DECL_INLINE (new_result);
|
|= DECL_INLINE (new_result);
|
||||||
|
@ -1642,12 +1672,12 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
|
||||||
|= DECL_DECLARED_INLINE_P (new_result);
|
|= DECL_DECLARED_INLINE_P (new_result);
|
||||||
check_redeclaration_exception_specification (newdecl, olddecl);
|
check_redeclaration_exception_specification (newdecl, olddecl);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* If the new declaration is a definition, update the file and
|
/* If the new declaration is a definition, update the file and
|
||||||
line information on the declaration, and also make
|
line information on the declaration, and also make
|
||||||
the old declaration the same definition. */
|
the old declaration the same definition. */
|
||||||
if (DECL_INITIAL (old_result) == NULL_TREE
|
if (DECL_INITIAL (new_result) != NULL_TREE)
|
||||||
&& DECL_INITIAL (new_result) != NULL_TREE)
|
|
||||||
{
|
{
|
||||||
DECL_SOURCE_LOCATION (olddecl)
|
DECL_SOURCE_LOCATION (olddecl)
|
||||||
= DECL_SOURCE_LOCATION (old_result)
|
= DECL_SOURCE_LOCATION (old_result)
|
||||||
|
@ -1805,9 +1835,30 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
|
||||||
new_template = NULL_TREE;
|
new_template = NULL_TREE;
|
||||||
if (DECL_LANG_SPECIFIC (newdecl) && DECL_LANG_SPECIFIC (olddecl))
|
if (DECL_LANG_SPECIFIC (newdecl) && DECL_LANG_SPECIFIC (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_INTERFACE_KNOWN (newdecl) |= DECL_INTERFACE_KNOWN (olddecl);
|
||||||
DECL_NOT_REALLY_EXTERN (newdecl) |= DECL_NOT_REALLY_EXTERN (olddecl);
|
DECL_NOT_REALLY_EXTERN (newdecl) |= DECL_NOT_REALLY_EXTERN (olddecl);
|
||||||
DECL_COMDAT (newdecl) |= DECL_COMDAT (olddecl);
|
DECL_COMDAT (newdecl) |= DECL_COMDAT (olddecl);
|
||||||
|
}
|
||||||
DECL_TEMPLATE_INSTANTIATED (newdecl)
|
DECL_TEMPLATE_INSTANTIATED (newdecl)
|
||||||
|= DECL_TEMPLATE_INSTANTIATED (olddecl);
|
|= 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
|
/* [temp.expl.spec/14] We don't inline explicit specialization
|
||||||
just because the primary template says so. */
|
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
|
else
|
||||||
{
|
{
|
||||||
if (DECL_PENDING_INLINE_INFO (newdecl) == 0)
|
if (DECL_PENDING_INLINE_INFO (newdecl) == 0)
|
||||||
|
@ -2123,9 +2181,25 @@ redeclaration_error_message (tree newdecl, tree olddecl)
|
||||||
{
|
{
|
||||||
if (DECL_NAME (olddecl) == NULL_TREE)
|
if (DECL_NAME (olddecl) == NULL_TREE)
|
||||||
return "%q#D not declared in class";
|
return "%q#D not declared in class";
|
||||||
else
|
else if (!GNU_INLINE_P (olddecl)
|
||||||
|
|| GNU_INLINE_P (newdecl))
|
||||||
return "redefinition of %q#D";
|
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;
|
return NULL;
|
||||||
}
|
}
|
||||||
else if (TREE_CODE (newdecl) == TEMPLATE_DECL)
|
else if (TREE_CODE (newdecl) == TEMPLATE_DECL)
|
||||||
|
@ -2151,9 +2225,24 @@ redeclaration_error_message (tree newdecl, tree olddecl)
|
||||||
ot = DECL_TEMPLATE_RESULT (olddecl);
|
ot = DECL_TEMPLATE_RESULT (olddecl);
|
||||||
if (DECL_TEMPLATE_INFO (ot))
|
if (DECL_TEMPLATE_INFO (ot))
|
||||||
ot = DECL_TEMPLATE_RESULT (template_for_substitution (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";
|
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):
|
/* Core issue #226 (C++0x):
|
||||||
|
|
||||||
If a friend function template declaration specifies a
|
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))
|
&& lookup_attribute ("noinline", attrs))
|
||||||
warning (0, "inline function %q+D given attribute noinline", decl1);
|
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))
|
if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (decl1))
|
||||||
/* This is a constructor, we must ensure that any default args
|
/* This is a constructor, we must ensure that any default args
|
||||||
introduced by this definition are propagated to the clones
|
introduced by this definition are propagated to the clones
|
||||||
|
@ -11071,7 +11168,8 @@ start_preparsed_function (tree decl1, tree attrs, int flags)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* This is a definition, not a reference.
|
/* This is a definition, not a reference.
|
||||||
So clear DECL_EXTERNAL. */
|
So clear DECL_EXTERNAL, unless this is a GNU extern inline. */
|
||||||
|
if (!GNU_INLINE_P (decl1))
|
||||||
DECL_EXTERNAL (decl1) = 0;
|
DECL_EXTERNAL (decl1) = 0;
|
||||||
|
|
||||||
if ((DECL_DECLARED_INLINE_P (decl1)
|
if ((DECL_DECLARED_INLINE_P (decl1)
|
||||||
|
|
|
@ -1718,8 +1718,8 @@ refer to the single copy in the library. Note that the two
|
||||||
definitions of the functions need not be precisely the same, although
|
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 they do not have the same effect your program may behave oddly.
|
||||||
|
|
||||||
If the function is neither @code{extern} nor @code{static}, then the
|
In C, if the function is neither @code{extern} nor @code{static}, then
|
||||||
function is compiled as a standalone function, as well as being
|
the function is compiled as a standalone function, as well as being
|
||||||
inlined where possible.
|
inlined where possible.
|
||||||
|
|
||||||
This is how GCC traditionally handled functions declared
|
This is how GCC traditionally handled functions declared
|
||||||
|
@ -1731,6 +1731,10 @@ preprocessor macros @code{__GNUC_GNU_INLINE__} or
|
||||||
@code{__GNUC_STDC_INLINE__} are defined. @xref{Inline,,An Inline
|
@code{__GNUC_STDC_INLINE__} are defined. @xref{Inline,,An Inline
|
||||||
Function is As Fast As a Macro}.
|
Function is As Fast As a Macro}.
|
||||||
|
|
||||||
|
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
|
@cindex @code{flatten} function attribute
|
||||||
@item flatten
|
@item flatten
|
||||||
Generally, inlining into a function is limited. For a function marked with
|
Generally, inlining into a function is limited. For a function marked with
|
||||||
|
|
|
@ -1,3 +1,15 @@
|
||||||
|
2007-08-27 Alexandre Oliva <aoliva@redhat.com>
|
||||||
|
|
||||||
|
* 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.
|
||||||
|
|
||||||
2007-08-27 Jason Merrill <jason@redhat.com>
|
2007-08-27 Jason Merrill <jason@redhat.com>
|
||||||
|
|
||||||
PR c++/31337
|
PR c++/31337
|
||||||
|
|
|
@ -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"
|
||||||
|
}
|
|
@ -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"
|
|
@ -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"
|
|
@ -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
|
|
@ -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" "" }
|
|
@ -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)
|
|
@ -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"
|
||||||
|
}
|
|
@ -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>;
|
|
@ -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);
|
Loading…
Reference in New Issue