Implement P0386R2 - C++17 inline variables

2016-10-11  Jakub Jelinek  <jakub@redhat.com>

	* dwarf2out.c (gen_member_die): Handle inline static data member
	definitions.
c-family/
	* c-cppbuiltin.c (c_cpp_builtins): Add __cpp_inline_variables.
cp/
	* cp-tree.h (struct lang_type): Shrink language field to 1 bit
	from 4.  Add var_declared_inline_p field.  Mention 2 spare bits.
	(DECL_VAR_DECLARED_INLINE_P): Define.
	(SET_DECL_VAR_DECLARED_INLINE_P): Define.
	(DECL_INLINE_VAR_P): Define.
	(diagnose_inline_vars_for_namespace): Declare.
	* decl.c (diagnose_inline_vars_for_namespace): New function.
	(duplicate_decls): For static data members copy
	DECL_DECLARED_CONSTEXPR_P.
	(redeclaration_error_message): Handle C++17 redundant redeclaration
	of constexpr static data member outside of class.
	(maybe_commonize_var): Handle inline variables.
	(check_initializer): Ignore inline variables for diagnostics.
	Adjust diagnostic wording for C++17.
	(make_rtl_for_nonlocal_decl): Allow in-class definition of
	inline static data members.
	(bad_specifiers): Don't diagnose inline on variables here.
	(grokvardecl): Add inlinep argument, non-static const inline variables
	are TREE_PUBLIC.
	(check_static_variable_definition): Return early also for inline
	variables.
	(grokdeclarator): Handle inline variables and inline static data
	members.
	* typeck2.c (store_init_value): Don't diagnose non-constant
	initializers for non-constexpr inline static data members.
	* decl2.c (vague_linkage_p): Return true for inline variables.
	(c_parse_final_cleanups): In-class declaration of inline static
	data members is a definition.  Call diagnose_inline_vars_for_namespace
	through walk_namespaces.
	* pt.c (instantiate_decl): Set pattern_defined for in-class definitions
	of inline static data members.

From-SVN: r241137
This commit is contained in:
Jason Merrill 2016-10-13 15:26:54 -04:00
parent fc0911e0b8
commit 14a2c9aac0
20 changed files with 712 additions and 31 deletions

View File

@ -1,3 +1,8 @@
2016-10-13 Jakub Jelinek <jakub@redhat.com>
* dwarf2out.c (gen_member_die): Handle inline static data member
definitions.
2016-10-13 Nathan Sidwell <nathan@acm.org>
* gcov-io.c (gcov_open): Fix documentation. Simplify setting

View File

@ -1,3 +1,7 @@
2016-10-13 Jason Merrill <jason@redhat.com>
* c-cppbuiltin.c (c_cpp_builtins): Add __cpp_inline_variables.
2016-10-13 Thomas Preud'homme <thomas.preudhomme@arm.com>
* c-cppbuiltin.c: Include memmodel.h.

View File

@ -935,6 +935,7 @@ c_cpp_builtins (cpp_reader *pfile)
cpp_define (pfile, "__cpp_constexpr=201603");
cpp_define (pfile, "__cpp_if_constexpr=201606");
cpp_define (pfile, "__cpp_capture_star_this=201603");
cpp_define (pfile, "__cpp_inline_variables=201606");
}
if (flag_concepts)
/* Use a value smaller than the 201507 specified in

View File

@ -1,3 +1,44 @@
2016-10-13 Jakub Jelinek <jakub@redhat.com>
Jason Merrill <jason@redhat.com>
Implement P0386R2 - C++17 inline variables
* cp-tree.h (struct lang_type): Shrink language field to 1 bit
from 4. Add var_declared_inline_p field. Mention 2 spare bits.
(DECL_VAR_DECLARED_INLINE_P): Define.
(SET_DECL_VAR_DECLARED_INLINE_P): Define.
(DECL_INLINE_VAR_P): Define.
(diagnose_inline_vars_for_namespace): Declare.
* decl.c (diagnose_inline_vars_for_namespace): New function.
(duplicate_decls): For static data members copy
DECL_DECLARED_CONSTEXPR_P.
(redeclaration_error_message): Handle C++17 redundant redeclaration
of constexpr static data member outside of class.
(maybe_commonize_var): Handle inline variables.
(check_initializer): Ignore inline variables for diagnostics.
Adjust diagnostic wording for C++17.
(make_rtl_for_nonlocal_decl): Allow in-class definition of
inline static data members.
(bad_specifiers): Don't diagnose inline on variables here.
(grokvardecl): Add inlinep argument, non-static const inline variables
are TREE_PUBLIC.
(check_static_variable_definition): Return early also for inline
variables.
(mark_inline_variable): New.
(grokdeclarator): Handle inline variables and inline static data
members.
* typeck2.c (store_init_value): Don't diagnose non-constant
initializers for non-constexpr inline static data members.
* decl2.c (vague_linkage_p): Return true for inline variables.
(c_parse_final_cleanups): In-class declaration of inline static
data members is a definition. Call diagnose_inline_vars_for_namespace
through walk_namespaces.
* pt.c (instantiate_decl): Set pattern_defined for in-class definitions
of inline static data members.
2016-10-13 Jason Merrill <jason@redhat.com>
* decl.c (mark_inline_variable): New.
2016-10-13 Thomas Preud'homme <thomas.preudhomme@arm.com>
* decl2.c: Include memmodel.h.

View File

@ -2214,7 +2214,7 @@ struct GTY(()) lang_type {
struct GTY(()) lang_decl_base {
unsigned selector : 16; /* Larger than necessary for faster access. */
ENUM_BITFIELD(languages) language : 4;
ENUM_BITFIELD(languages) language : 1;
unsigned use_template : 2;
unsigned not_really_extern : 1; /* var or fn */
unsigned initialized_in_class : 1; /* var or fn */
@ -2227,7 +2227,8 @@ struct GTY(()) lang_decl_base {
unsigned odr_used : 1; /* var or fn */
unsigned u2sel : 1;
unsigned concept_p : 1; /* applies to vars and functions */
/* 0 spare bits */
unsigned var_declared_inline_p : 1; /* var */
/* 2 spare bits */
};
/* True for DECL codes which have template info and access. */
@ -3607,6 +3608,23 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
#define CP_DECL_THREADPRIVATE_P(DECL) \
(DECL_LANG_SPECIFIC (VAR_DECL_CHECK (DECL))->u.base.threadprivate_or_deleted_p)
/* Nonzero if NODE is a VAR_DECL which has been declared inline. */
#define DECL_VAR_DECLARED_INLINE_P(NODE) \
(DECL_LANG_SPECIFIC (VAR_DECL_CHECK (NODE)) \
? DECL_LANG_SPECIFIC (NODE)->u.base.var_declared_inline_p \
: false)
#define SET_DECL_VAR_DECLARED_INLINE_P(NODE) \
(DECL_LANG_SPECIFIC (VAR_DECL_CHECK (NODE))->u.base.var_declared_inline_p \
= true)
/* Nonzero if NODE is an inline VAR_DECL. In C++17, static data members
declared with constexpr specifier are implicitly inline variables. */
#define DECL_INLINE_VAR_P(NODE) \
(DECL_VAR_DECLARED_INLINE_P (NODE) \
|| (cxx_dialect >= cxx1z \
&& DECL_DECLARED_CONSTEXPR_P (NODE) \
&& DECL_CLASS_SCOPE_P (NODE)))
/* Nonzero if DECL was declared with '= delete'. */
#define DECL_DELETED_FN(DECL) \
(LANG_DECL_FN_CHECK (DECL)->min.base.threadprivate_or_deleted_p)
@ -5799,6 +5817,7 @@ typedef int (*walk_namespaces_fn) (tree, void *);
extern int walk_namespaces (walk_namespaces_fn,
void *);
extern int wrapup_globals_for_namespace (tree, void *);
extern int diagnose_inline_vars_for_namespace (tree, void *);
extern tree create_implicit_typedef (tree, tree);
extern int local_variable_p (const_tree);
extern tree register_dtor_fn (tree);

View File

@ -68,7 +68,7 @@ static int unary_op_p (enum tree_code);
static void push_local_name (tree);
static tree grok_reference_init (tree, tree, tree, int);
static tree grokvardecl (tree, tree, tree, const cp_decl_specifier_seq *,
int, int, int, tree);
int, int, int, int, tree);
static int check_static_variable_definition (tree, tree);
static void record_unknown_type (tree, const char *);
static tree builtin_function_1 (tree, tree, bool);
@ -937,6 +937,27 @@ wrapup_globals_for_namespace (tree name_space, void* data ATTRIBUTE_UNUSED)
/* Write out any globals that need to be output. */
return wrapup_global_declarations (vec, len);
}
/* Diagnose odr-used extern inline variables without definitions
in the current TU. */
int
diagnose_inline_vars_for_namespace (tree name_space, void *)
{
cp_binding_level *level = NAMESPACE_LEVEL (name_space);
vec<tree, va_gc> *statics = level->static_decls;
tree decl;
unsigned int i;
FOR_EACH_VEC_SAFE_ELT (statics, i, decl)
if (VAR_P (decl)
&& DECL_EXTERNAL (decl)
&& DECL_INLINE_VAR_P (decl)
&& DECL_ODR_USED (decl))
error_at (DECL_SOURCE_LOCATION (decl),
"odr-used inline variable %qD is not defined", decl);
return 0;
}
/* In C++, you don't have to write `struct S' to refer to `S'; you
can just use `S'. We accomplish this by creating a TYPE_DECL as
@ -2098,6 +2119,9 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
|= DECL_NONTRIVIALLY_INITIALIZED_P (olddecl);
DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (newdecl)
|= DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (olddecl);
if (DECL_CLASS_SCOPE_P (olddecl))
DECL_DECLARED_CONSTEXPR_P (newdecl)
|= DECL_DECLARED_CONSTEXPR_P (olddecl);
/* Merge the threadprivate attribute from OLDDECL into NEWDECL. */
if (DECL_LANG_SPECIFIC (olddecl)
@ -2882,6 +2906,27 @@ redeclaration_error_message (tree newdecl, tree olddecl)
is valid. */
if (DECL_EXTERNAL (newdecl) || DECL_EXTERNAL (olddecl))
return NULL;
/* Static data member declared outside a class definition
if the variable is defined within the class with constexpr
specifier is declaration rather than definition (and
deprecated). */
if (cxx_dialect >= cxx1z
&& DECL_CLASS_SCOPE_P (olddecl)
&& DECL_DECLARED_CONSTEXPR_P (olddecl)
&& !DECL_INITIAL (newdecl))
{
DECL_EXTERNAL (newdecl) = 1;
/* For now, only warn with explicit -Wdeprecated. */
if (global_options_set.x_warn_deprecated
&& warning_at (DECL_SOURCE_LOCATION (newdecl), OPT_Wdeprecated,
"redundant redeclaration of %<constexpr%> static "
"data member %qD", newdecl))
inform (DECL_SOURCE_LOCATION (olddecl),
"previous declaration of %qD", olddecl);
return NULL;
}
/* Reject two definitions. */
return G_("redefinition of %q#D");
}
@ -5405,11 +5450,12 @@ maybe_commonize_var (tree decl)
{
/* Static data in a function with comdat linkage also has comdat
linkage. */
if (TREE_STATIC (decl)
/* Don't mess with __FUNCTION__. */
&& ! DECL_ARTIFICIAL (decl)
&& DECL_FUNCTION_SCOPE_P (decl)
&& vague_linkage_p (DECL_CONTEXT (decl)))
if ((TREE_STATIC (decl)
/* Don't mess with __FUNCTION__. */
&& ! DECL_ARTIFICIAL (decl)
&& DECL_FUNCTION_SCOPE_P (decl)
&& vague_linkage_p (DECL_CONTEXT (decl)))
|| (TREE_PUBLIC (decl) && DECL_INLINE_VAR_P (decl)))
{
if (flag_weak)
{
@ -5435,10 +5481,17 @@ maybe_commonize_var (tree decl)
be merged. */
TREE_PUBLIC (decl) = 0;
DECL_COMMON (decl) = 0;
const char *msg;
if (DECL_INLINE_VAR_P (decl))
msg = G_("sorry: semantics of inline variable "
"%q#D are wrong (you%'ll wind up with "
"multiple copies)");
else
msg = G_("sorry: semantics of inline function "
"static data %q#D are wrong (you%'ll wind "
"up with multiple copies)");
if (warning_at (DECL_SOURCE_LOCATION (decl), 0,
"sorry: semantics of inline function static "
"data %q#D are wrong (you%'ll wind up "
"with multiple copies)", decl))
msg, decl))
inform (DECL_SOURCE_LOCATION (decl),
"you can work around this by removing the initializer");
}
@ -6282,15 +6335,19 @@ check_initializer (tree decl, tree init, int flags, vec<tree, va_gc> **cleanups)
TREE_CONSTANT (decl) = false;
}
if (init_code && DECL_IN_AGGR_P (decl))
if (init_code
&& (DECL_IN_AGGR_P (decl) && !DECL_VAR_DECLARED_INLINE_P (decl)))
{
static int explained = 0;
if (cxx_dialect < cxx11)
error ("initializer invalid for static member with constructor");
else
else if (cxx_dialect < cxx1z)
error ("non-constant in-class initialization invalid for static "
"member %qD", decl);
else
error ("non-constant in-class initialization invalid for non-inline "
"static member %qD", decl);
if (!explained)
{
inform (input_location,
@ -6346,7 +6403,9 @@ make_rtl_for_nonlocal_decl (tree decl, tree init, const char* asmspec)
/* An in-class declaration of a static data member should be
external; it is only a declaration, and not a definition. */
if (init == NULL_TREE)
gcc_assert (DECL_EXTERNAL (decl) || !TREE_PUBLIC (decl));
gcc_assert (DECL_EXTERNAL (decl)
|| !TREE_PUBLIC (decl)
|| DECL_INLINE_VAR_P (decl));
}
/* We don't create any RTL for local variables. */
@ -7745,8 +7804,6 @@ bad_specifiers (tree object,
case BSP_VAR:
if (virtualp)
error ("%qD declared as a %<virtual%> variable", object);
if (inlinep)
error ("%qD declared as an %<inline%> variable", object);
if (quals)
error ("%<const%> and %<volatile%> function specifiers on "
"%qD invalid in variable declaration", object);
@ -8456,6 +8513,7 @@ grokvardecl (tree type,
const cp_decl_specifier_seq *declspecs,
int initialized,
int flags,
int inlinep,
int template_count,
tree scope)
{
@ -8520,7 +8578,9 @@ grokvardecl (tree type,
else if (toplevel_bindings_p ())
{
TREE_PUBLIC (decl) = (declspecs->storage_class != sc_static
&& (DECL_THIS_EXTERN (decl) || ! constp));
&& (DECL_THIS_EXTERN (decl)
|| ! constp
|| inlinep));
TREE_STATIC (decl) = ! DECL_EXTERNAL (decl);
}
/* Not at top level, only `static' makes a static definition. */
@ -8692,8 +8752,10 @@ check_static_variable_definition (tree decl, tree type)
if (dependent_type_p (type))
return 0;
/* If DECL is declared constexpr, we'll do the appropriate checks
in check_initializer. */
if (DECL_P (decl) && DECL_DECLARED_CONSTEXPR_P (decl))
in check_initializer. Similarly for inline static data members. */
if (DECL_P (decl)
&& (DECL_DECLARED_CONSTEXPR_P (decl)
|| DECL_VAR_DECLARED_INLINE_P (decl)))
return 0;
else if (cxx_dialect >= cxx11 && !INTEGRAL_OR_ENUMERATION_TYPE_P (type))
{
@ -9241,6 +9303,29 @@ check_var_type (tree identifier, tree type)
return type;
}
/* Handle declaring DECL as an inline variable. */
static void
mark_inline_variable (tree decl)
{
bool inlinep = true;
if (! toplevel_bindings_p ())
{
error ("%<inline%> specifier invalid for variable "
"%qD declared at block scope", decl);
inlinep = false;
}
else if (cxx_dialect < cxx1z)
pedwarn (DECL_SOURCE_LOCATION (decl), 0,
"inline variables are only available "
"with -std=c++1z or -std=gnu++1z");
if (inlinep)
{
retrofit_lang_decl (decl);
SET_DECL_VAR_DECLARED_INLINE_P (decl);
}
}
/* Given declspecs and a declarator (abstract or otherwise), determine
the name and type of the object declared and construct a DECL node
for it.
@ -11349,11 +11434,6 @@ grokdeclarator (const cp_declarator *declarator,
: input_location,
VAR_DECL, unqualified_id, type);
set_linkage_for_static_data_member (decl);
/* Even if there is an in-class initialization, DECL
is considered undefined until an out-of-class
definition is provided. */
DECL_EXTERNAL (decl) = 1;
if (thread_p)
{
CP_DECL_THREAD_LOCAL_P (decl) = true;
@ -11371,6 +11451,17 @@ grokdeclarator (const cp_declarator *declarator,
"initializer", decl);
constexpr_p = false;
}
if (inlinep)
mark_inline_variable (decl);
if (!DECL_VAR_DECLARED_INLINE_P (decl)
&& !(cxx_dialect >= cxx1z && constexpr_p))
/* Even if there is an in-class initialization, DECL
is considered undefined until an out-of-class
definition is provided, unless this is an inline
variable. */
DECL_EXTERNAL (decl) = 1;
}
else
{
@ -11411,7 +11502,8 @@ grokdeclarator (const cp_declarator *declarator,
bad_specifiers (decl, BSP_FIELD, virtualp,
memfn_quals != TYPE_UNQUALIFIED,
inlinep, friendp, raises != NULL_TREE);
staticp ? false : inlinep, friendp,
raises != NULL_TREE);
}
}
else if (TREE_CODE (type) == FUNCTION_TYPE
@ -11535,6 +11627,7 @@ grokdeclarator (const cp_declarator *declarator,
declspecs,
initialized,
((type_quals & TYPE_QUAL_CONST) != 0) | (2 * concept_p),
inlinep,
template_count,
ctype ? ctype : in_namespace);
if (decl == NULL_TREE)
@ -11573,6 +11666,9 @@ grokdeclarator (const cp_declarator *declarator,
decl);
constexpr_p = false;
}
if (inlinep)
mark_inline_variable (decl);
}
if (VAR_P (decl) && !initialized)

View File

@ -1827,7 +1827,8 @@ vague_linkage_p (tree decl)
|| (TREE_CODE (decl) == FUNCTION_DECL
&& DECL_DECLARED_INLINE_P (decl))
|| (DECL_LANG_SPECIFIC (decl)
&& DECL_TEMPLATE_INSTANTIATION (decl)))
&& DECL_TEMPLATE_INSTANTIATION (decl))
|| (VAR_P (decl) && DECL_INLINE_VAR_P (decl)))
return true;
else if (DECL_FUNCTION_SCOPE_P (decl))
/* A local static in an inline effectively has vague linkage. */
@ -4711,7 +4712,7 @@ c_parse_final_cleanups (void)
{
if (var_finalized_p (decl) || DECL_REALLY_EXTERN (decl)
/* Don't write it out if we haven't seen a definition. */
|| DECL_IN_AGGR_P (decl))
|| (DECL_IN_AGGR_P (decl) && !DECL_INLINE_VAR_P (decl)))
continue;
import_export_decl (decl);
/* If this static data member is needed, provide it to the
@ -4728,6 +4729,8 @@ c_parse_final_cleanups (void)
}
while (reconsider);
walk_namespaces (diagnose_inline_vars_for_namespace, /*data=*/0);
lower_var_init ();
generate_mangling_aliases ();

View File

@ -21923,7 +21923,8 @@ instantiate_decl (tree d, int defer_ok,
{
deleted_p = false;
if (DECL_CLASS_SCOPE_P (code_pattern))
pattern_defined = ! DECL_IN_AGGR_P (code_pattern);
pattern_defined = (! DECL_IN_AGGR_P (code_pattern)
|| DECL_INLINE_VAR_P (code_pattern));
else
pattern_defined = ! DECL_EXTERNAL (code_pattern);
}

View File

@ -807,7 +807,7 @@ store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags)
bool const_init;
value = instantiate_non_dependent_expr (value);
if (DECL_DECLARED_CONSTEXPR_P (decl)
|| DECL_IN_AGGR_P (decl))
|| (DECL_IN_AGGR_P (decl) && !DECL_VAR_DECLARED_INLINE_P (decl)))
{
/* Diagnose a non-constant initializer for constexpr. */
if (processing_template_decl

View File

@ -22653,7 +22653,18 @@ gen_member_die (tree type, dw_die_ref context_die)
child = lookup_decl_die (member);
if (child)
splice_child_die (context_die, child);
{
/* Handle inline static data members, which only have in-class
declarations. */
if (child->die_tag == DW_TAG_variable
&& child->die_parent == comp_unit_die ())
{
reparent_child (child, context_die);
child->die_tag = DW_TAG_member;
}
else
splice_child_die (context_die, child);
}
/* Do not generate standard DWARF for variant parts if we are generating
the corresponding GNAT encodings: DIEs generated for both would

View File

@ -1,3 +1,13 @@
2016-10-13 Jakub Jelinek <jakub@redhat.com>
* g++.dg/cpp1z/inline-var1.C: New test.
* g++.dg/cpp1z/inline-var1a.C: New test.
* g++.dg/cpp1z/inline-var1.h: New file.
* g++.dg/cpp1z/inline-var2.C: New test.
* g++.dg/cpp1z/inline-var3.C: New test.
* g++.dg/concepts/decl-diagnose.C (struct X): Expect also error about
uninitialized const.
2016-10-13 Sandra Loosemore <sandra@codesourcery.com>
* gcc.target/arm/scd42-1.c: Skip if -mcpu incompatible with

View File

@ -16,6 +16,7 @@ struct X
template<typename T>
static concept bool f6() { return true; } // { dg-error "a concept cannot be a member function" }
static concept bool x; // { dg-error "declared 'concept'" }
// { dg-error "uninitialized const" "" { target *-*-* } .-1 }
concept int x2; // { dg-error "declared 'concept'" }
concept ~X(); // { dg-error "a destructor cannot be 'concept'" }
concept X(); // { dg-error "a constructor cannot be 'concept'" }

View File

@ -6,3 +6,5 @@ struct A
constexpr A() {}
static constexpr A a[2] = {}; // { dg-error "22:elements of array 'constexpr const A A::a \\\[2\\\]' have incomplete type" }
};
// { dg-prune-output "storage size" }

View File

@ -356,6 +356,12 @@
# error "__cpp_aligned_new != 201606"
#endif
#ifndef __cpp_inline_variables
# error "__cpp_inline_variables"
#elif __cpp_inline_variables != 201606
# error "__cpp_inline_variables != 201606"
#endif
#ifndef __cpp_capture_star_this
# error "__cpp_capture_star_this"
#elif __cpp_capture_star_this != 201603

View File

@ -0,0 +1,216 @@
// { dg-do run }
// { dg-options "-std=c++1z -Wno-deprecated" }
// { dg-require-weak "" }
// { dg-additional-sources "inline-var1a.C" }
#include "inline-var1.h"
static inline int var19 = bar (0);
static int inline var20 = bar (1);
extern inline int var23;
inline int var21 = foo (6);
inline int var22 = foo (7);
extern inline int var23, var22;
inline int var23 = foo (8);
static int v, w;
int
foo (int x)
{
if (x != v++)
__builtin_abort ();
return 36 + x;
}
int
bar (int x)
{
if (v < 6)
__builtin_abort ();
if ((x >> 4) != (w >> 4))
{
if ((x & 15) != 0 || (w & 15) != 2)
__builtin_abort ();
w = x + 1;
}
else if (x != w++)
__builtin_abort ();
return 46 + x;
}
int &ref1 = var1;
int &ref2 = N::var2;
const int &ref3 = S::var3;
int &ref4 = S::var4;
const int &ref5 = S::var5;
const int &ref6 = N::var6;
int &ref7 = var7;
double &ref8 = N::var8;
double &ref9 = S::var9;
const int &ref11 = S::var11;
int &ref12 = var12;
int &ref13 = var13;
int &ref14 = U::var14;
T &ref15 = U::var15;
T &ref16 = U::var16;
int &ref17 = U::var17;
const double &ref18 = U::var18;
int &ref19 = var19;
int &ref20 = var20;
int &ref21 = var21;
int &ref22 = var22;
int &ref23 = var23;
const int &ref24 = Y<int>::var24;
int &ref25 = Y<int>::var25;
int &ref26 = Y<int>::var26;
int &ref27 = var27<int>;
const int &ref28 = Y<int>::var28;
const char &ref24a = Y<char>::var24;
char &ref25a = Y<char>::var25;
int &ref26a = Y<char>::var26;
char &ref27a = var27<char>;
const char &ref28a = Y<char>::var28;
extern int &alt1;
extern int &alt2;
extern const int &alt3;
extern int &alt4;
extern const int &alt5;
extern const int &alt6;
extern int &alt7;
extern double &alt8;
extern double &alt9;
extern const int &alt11;
extern int &alt12;
extern int &alt13;
extern int &alt14;
extern T &alt15;
extern T &alt16;
extern int &alt17;
extern const double &alt18;
extern int &alt19;
extern int &alt20;
extern int &alt21;
extern int &alt22;
extern int &alt23;
extern const int &alt24;
extern int &alt25;
extern int &alt26;
extern int &alt27;
extern const int &alt28;
extern const char &alt24a;
extern char &alt25a;
extern int &alt26a;
extern char &alt27a;
extern const char &alt28a;
int
main ()
{
if (v != 9)
__builtin_abort ();
if (var1 != 4
|| N::var2 != 0
|| S::var3 != 5
|| S::var4 != 6
|| S::var5 != 7
|| N::var6 != 8
|| var7 != 9
|| N::var8 != 2.0
|| S::var9 != 3.0
|| sizeof (N::var10) != 1
|| S::var11 != 11
|| var12 != 36
|| var13 != 37
|| U::var14 != 38
|| U::var15.t != 39
|| U::var16.t != 40
|| U::var17 != 41
|| U::var18 != 4.0
|| var19 != 46
|| var20 != 47
|| var21 != 42
|| var22 != 43
|| var23 != 44
|| Y<int>::var24 != 6
|| Y<int>::var25 != 7
|| Y<int>::var26 != 8
|| var27<int> != 9
|| Y<int>::var28 != 10
|| Y<char>::var24 != 6
|| Y<char>::var25 != 7
|| Y<char>::var26 != 8
|| var27<char> != 9
|| Y<char>::var28 != 10)
__builtin_abort ();
if (ref1 != 4
|| ref2 != 0
|| ref3 != 5
|| ref4 != 6
|| ref5 != 7
|| ref6 != 8
|| ref7 != 9
|| alt7 != 9
|| ref8 != 2.0
|| alt8 != 2.0
|| ref9 != 3.0
|| ref11 != 11
|| ref12 != 36
|| ref13 != 37
|| ref14 != 38
|| ref15.t != 39
|| ref16.t != 40
|| ref17 != 41
|| ref18 != 4.0
|| ref19 != 46
|| alt19 != 62
|| ref20 != 47
|| alt20 != 63
|| ref21 != 42
|| ref22 != 43
|| ref23 != 44
|| ref24 != 6
|| ref25 != 7
|| ref26 != 8
|| ref27 != 9
|| ref28 != 10
|| ref24a != 6
|| ref25a != 7
|| ref26a != 8
|| ref27a != 9
|| ref28a != 10)
__builtin_abort ();
if (&ref1 != &alt1
|| &ref2 != &alt2
|| &ref3 != &alt3
|| &ref4 != &alt4
|| &ref5 != &alt5
|| &ref6 != &alt6
|| &ref7 == &alt7
|| &ref8 == &alt8
|| &ref9 != &alt9
|| &ref11 != &alt11
|| &ref12 != &alt12
|| &ref13 != &alt13
|| &ref14 != &alt14
|| &ref15 != &alt15
|| &ref16 != &alt16
|| &ref17 != &alt17
|| &ref18 != &alt18
|| &ref19 == &alt19
|| &ref20 == &alt20
|| &ref21 != &alt21
|| &ref22 != &alt22
|| &ref23 != &alt23
|| &ref24 != &alt24
|| &ref25 != &alt25
|| &ref26 != &alt26
|| &ref27 != &alt27
|| &ref28 != &alt28
|| &ref24a != &alt24a
|| &ref25a != &alt25a
|| &ref26a != &alt26a
|| &ref27a != &alt27a
|| &ref28a != &alt28a)
__builtin_abort ();
}

View File

@ -0,0 +1,46 @@
inline int var1 = 4;
static inline int var7 = 9;
namespace N
{
int inline var2;
inline const int var6 = 8;
static inline double var8 = 2.0;
extern inline char var10;
}
struct S
{
static constexpr int var3 = 5;
static inline int var4 = 6;
static constexpr int var5 = 7;
static inline double var9 = 3.0;
static constexpr inline int var11 = 11;
};
const int S::var3;
const int S::var3;
extern int foo (int);
extern int bar (int);
struct T { T () { t = foo (3); } T (int x) { t = foo (x); } int t; };
inline int var12 = foo (0);
int inline var13 = foo (1);
struct U
{
static inline int var14 = foo (2);
static inline T var15;
static inline T var16 = 4;
static int inline var17 = foo (5);
static constexpr double var18 = 4.0;
};
template <typename T>
struct Y
{
static constexpr T var24 = 6;
static inline T var25 = 7;
static inline int var26 = 8;
static constexpr T var28 = 10;
};
template <typename T>
const T Y<T>::var24;
template <typename T>
const T Y<T>::var24;
template <typename T>
inline T var27 = 9;

View File

@ -0,0 +1,44 @@
// { dg-do compile }
// { dg-options "-std=c++1z -Wno-deprecated -g" }
#include "inline-var1.h"
static inline int var19 = bar (16);
static int inline var20 = bar (17);
inline int var21 = foo (6);
inline int var22 = foo (7);
extern inline int var23;
inline int var23 = foo (8);
int &alt1 = var1;
int &alt2 = N::var2;
const int &alt3 = S::var3;
int &alt4 = S::var4;
const int &alt5 = S::var5;
const int &alt6 = N::var6;
int &alt7 = var7;
double &alt8 = N::var8;
double &alt9 = S::var9;
const int &alt11 = S::var11;
int &alt12 = var12;
int &alt13 = var13;
int &alt14 = U::var14;
T &alt15 = U::var15;
T &alt16 = U::var16;
int &alt17 = U::var17;
const double &alt18 = U::var18;
int &alt19 = var19;
int &alt20 = var20;
int &alt21 = var21;
int &alt22 = var22;
int &alt23 = var23;
const int &alt24 = Y<int>::var24;
int &alt25 = Y<int>::var25;
int &alt26 = Y<int>::var26;
int &alt27 = var27<int>;
const int &alt28 = Y<int>::var28;
const char &alt24a = Y<char>::var24;
char &alt25a = Y<char>::var25;
int &alt26a = Y<char>::var26;
char &alt27a = var27<char>;
const char &alt28a = Y<char>::var28;

View File

@ -0,0 +1,117 @@
// { dg-do compile { target c++11 } }
// { dg-options "-Wdeprecated" }
inline int var1 = 4; // { dg-warning "inline variables are only available with" "" { target c++14_down } }
static inline int var7 = 9; // { dg-warning "inline variables are only available with" "" { target c++14_down } }
namespace N
{
int inline var2; // { dg-warning "inline variables are only available with" "" { target c++14_down } }
inline const int var6 = 8; // { dg-warning "inline variables are only available with" "" { target c++14_down } }
static inline double var8 = 2.0; // { dg-warning "inline variables are only available with" "" { target c++14_down } }
extern inline char var10; // { dg-warning "inline variables are only available with" "" { target c++14_down } }
}
struct S
{
static constexpr int var3 = 5;
static inline int var4 = 6; // { dg-warning "inline variables are only available with" "" { target c++14_down } }
static constexpr int var5 = 7;
static inline double var9 = 3.0; // { dg-warning "inline variables are only available with" "" { target c++14_down } }
static constexpr inline int var11 = 11; // { dg-warning "inline variables are only available with" "" { target c++14_down } }
};
const int S::var3; // { dg-warning "redundant redeclaration of" "" { target c++1z } }
const int S::var3; // { dg-error "redefinition of" "" { target c++14_down } }
extern int foo (int); // { dg-warning "redundant redeclaration of" "" { target c++1z } .-1 }
extern int bar (int);
struct T { T () { t = foo (3); } T (int x) { t = foo (x); } int t; };
inline int var12 = foo (0); // { dg-warning "inline variables are only available with" "" { target c++14_down } }
int inline var13 = foo (1); // { dg-warning "inline variables are only available with" "" { target c++14_down } }
struct U
{
static inline int var14 = foo (2); // { dg-warning "inline variables are only available with" "" { target c++14_down } }
static inline T var15; // { dg-warning "inline variables are only available with" "" { target c++14_down } }
static inline T var16 = 4; // { dg-warning "inline variables are only available with" "" { target c++14_down } }
static int inline var17 = foo (5); // { dg-warning "inline variables are only available with" "" { target c++14_down } }
static constexpr double var18 = 4.0;
};
extern inline int var19; // { dg-warning "inline variables are only available with" "" { target c++14_down } }
extern inline int var20; // { dg-warning "inline variables are only available with" "" { target c++14_down } }
int &ref19 = var19; // { dg-error "odr-used inline variable 'var19' is not defined" "" { target *-*-* } .-2 }
int sz20 = sizeof (var20);
struct V
{
static struct A var21; // { dg-warning "inline variables are only available with" "" { target c++14_down } .+1 }
static inline struct B var22; // { dg-error "has incomplete type" }
static inline struct C var23 = {}; // { dg-error "has incomplete type" }
}; // { dg-warning "inline variables are only available with" "" { target c++14_down } .-1 }
struct W
{
static inline int var24; // { dg-warning "inline variables are only available with" "" { target c++14_down } }
static inline const int var25; // { dg-warning "inline variables are only available with" "" { target c++14_down } }
// { dg-error "uninitialized const" "" { target *-*-* } .-1 }
static inline int var26 = 5; // { dg-warning "inline variables are only available with" "" { target c++14_down } }
static inline const int var27 = 6; // { dg-warning "inline variables are only available with" "" { target c++14_down } }
static inline double var28 = { 4.0 }; // { dg-warning "inline variables are only available with" "" { target c++14_down } }
static const inline double var29 = { 5.0 }; // { dg-warning "inline variables are only available with" "" { target c++14_down } }
};
int W::var24; // { dg-error "redefinition of" }
const int W::var25; // { dg-error "redefinition of" }
int W::var26; // { dg-error "redefinition of" }
const int W::var27; // { dg-error "redefinition of" }
double W::var28; // { dg-error "redefinition of" }
double const W::var29; // { dg-error "redefinition of" }
struct X
{
inline int var30; // { dg-error "'var30' declared as an 'inline' field" }
};
inline typedef int TT; // { dg-error "'TT' declared as an 'inline' type" }
int
foo (inline int var31) // { dg-error "'var31' declared as an 'inline' parameter" }
{
inline int var32; // { dg-error "'inline' specifier invalid for variable 'var32' declared at block scope" }
static inline int var33; // { dg-error "'inline' specifier invalid for variable 'var33' declared at block scope" }
}
template <typename A, typename B, typename C>
struct Y
{
static A var34; // { dg-warning "inline variables are only available with" "" { target c++14_down } .+1 }
static inline B var35; // { dg-error "has incomplete type" }
static inline C var36; // { dg-error "has incomplete type" }
}; // { dg-warning "inline variables are only available with" "" { target c++14_down } .-1 }
struct A;
struct B;
struct C;
Y<A, B, C> y;
A *ptr34 = &Y<A, B, C>::var34;
B *ptr35 = &Y<A, B, C>::var35;
C *ptr36 = &Y<A, B, C>::var36;
template <int N>
struct Z
{
static inline int var37; // { dg-warning "inline variables are only available with" "" { target c++14_down } }
static inline const int var38; // { dg-warning "inline variables are only available with" "" { target c++14_down } }
// { dg-error "uninitialized const" "" { target *-*-* } .-1 }
static inline int var39 = 5; // { dg-warning "inline variables are only available with" "" { target c++14_down } }
static inline const int var40 = 6; // { dg-warning "inline variables are only available with" "" { target c++14_down } }
static inline double var41 = { 4.0 }; // { dg-warning "inline variables are only available with" "" { target c++14_down } }
static const inline double var42 = { 5.0 }; // { dg-warning "inline variables are only available with" "" { target c++14_down } }
static constexpr int var43 = 5;
static constexpr inline int var44 = 5; // { dg-warning "inline variables are only available with" "" { target c++14_down } }
};
template <int N>
int Z<N>::var37; // { dg-error "redefinition of" }
template <int N>
const int Z<N>::var38; // { dg-error "redefinition of" }
const int &ref38 = Z<0>::var38;
template <int N>
int Z<N>::var39; // { dg-error "redefinition of" }
template <int N>
const int Z<N>::var40; // { dg-error "redefinition of" }
template <int N>
double Z<N>::var41; // { dg-error "redefinition of" }
template <int N>
double const Z<N>::var42; // { dg-error "redefinition of" }
template <int N>
const int Z<N>::var43; // { dg-warning "redundant redeclaration of" "" { target c++1z } }
template <int N> // { dg-warning "redundant redeclaration of" "" { target c++1z } .+1 }
const int Z<N>::var43; // { dg-error "redefinition of" "" { target c++14_down } }
Z<0> z;

View File

@ -0,0 +1,58 @@
// { dg-do compile }
// { dg-options "-g0" }
// Verify that inline variables and static data members that aren't odr-used
// aren't emitted into assembly even at -O0.
// { dg-final { scan-assembler-not "inlvarvariable" } }
inline int inlvarvariable1 = 1; // { dg-warning "inline variables are only available with" "" { target c++14_down } }
const inline int inlvarvariable2 = 2; // { dg-warning "inline variables are only available with" "" { target c++14_down } }
namespace N
{
int inline inlvarvariable3; // { dg-warning "inline variables are only available with" "" { target c++14_down } }
const int inline inlvarvariable4 = 4; // { dg-warning "inline variables are only available with" "" { target c++14_down } }
}
struct S
{
static inline double inlvarvariable5 = 5.0; // { dg-warning "inline variables are only available with" "" { target c++14_down } }
#if __cplusplus >= 201103L
static constexpr int inlvarvariable6 = 6;
static inline constexpr int inlvarvariable7 = 7; // { dg-warning "inline variables are only available with" "" { target { c++11 && c++14_down } } }
#endif
};
template <int N> // { dg-warning "variable templates only available with" "" { target c++11_down } .+1 }
inline int inlvarvariable8; // { dg-warning "inline variables are only available with" "" { target c++14_down } }
template <int N> // { dg-warning "variable templates only available with" "" { target c++11_down } .+1 }
const int inline inlvarvariable9 = 9; // { dg-warning "inline variables are only available with" "" { target c++14_down } }
namespace N
{
template <int N> // { dg-warning "variable templates only available with" "" { target c++11_down } .+1 }
int inline inlvarvariable10 = 10; // { dg-warning "inline variables are only available with" "" { target c++14_down } }
template <int N> // { dg-warning "variable templates only available with" "" { target c++11_down } .+1 }
const inline double inlvarvariable11 = 11.0; // { dg-warning "inline variables are only available with" "" { target c++14_down } }
}
template <int N>
struct T
{
static inline int inlvarvariable12 = 12; // { dg-warning "inline variables are only available with" "" { target c++14_down } }
#if __cplusplus >= 201103L
static constexpr int inlvarvariable13 = 13;
static inline constexpr double inlvarvariable14 = 14.0; // { dg-warning "inline variables are only available with" "" { target { c++11 && c++14_down } } }
#endif
};
#if __cplusplus < 201103L
#define decltype(x) int
#endif
decltype (inlvarvariable1) v1 = inlvarvariable2 + sizeof (inlvarvariable1);
decltype (N::inlvarvariable3) v2 = N::inlvarvariable4 + sizeof (N::inlvarvariable3);
#if __cplusplus >= 201103L
decltype (S::inlvarvariable6) v3 = sizeof (S::inlvarvariable5) + S::inlvarvariable6 + S::inlvarvariable7;
#else
int v3 = sizeof (S::inlvarvariable5);
#endif
decltype (inlvarvariable8<2>) v4 = inlvarvariable9<2> + sizeof (inlvarvariable8<2>);
decltype (N::inlvarvariable10<0>) v5 = sizeof (N::inlvarvariable10<0>) + sizeof (N::inlvarvariable11<0>);
#if __cplusplus >= 201103L
decltype (T<-1>::inlvarvariable12) v6 = sizeof (T<-1>::inlvarvariable14) + sizeof (T<-1>::inlvarvariable12) + T<-1>::inlvarvariable13;
#else
int v6 = sizeof (T<-1>::inlvarvariable12);
#endif

View File

@ -1,7 +1,7 @@
// { dg-do assemble }
// GROUPS passed miscellaneous
// test that use of `inline' is forbidden when it should be
inline int i;// { dg-error "" } .*
inline int i;// { dg-error "" "" { target c++14_down } } .*
struct c { inline int i; };// { dg-error "" } .*
int foo (inline int i);// { dg-error "" } .*
inline class c; // { dg-error "'inline' can only be specified for functions" } inline