+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
+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.
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
+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.
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 */
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. */
#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)
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);
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);
/* 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;
+}
\f
/* 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
|= 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)
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");
}
{
/* 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)
{
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");
}
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,
/* 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. */
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);
const cp_decl_specifier_seq *declspecs,
int initialized,
int flags,
+ int inlinep,
int template_count,
tree scope)
{
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. */
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))
{
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.
: 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;
"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
{
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
declspecs,
initialized,
((type_quals & TYPE_QUAL_CONST) != 0) | (2 * concept_p),
+ inlinep,
template_count,
ctype ? ctype : in_namespace);
if (decl == NULL_TREE)
decl);
constexpr_p = false;
}
+
+ if (inlinep)
+ mark_inline_variable (decl);
}
if (VAR_P (decl) && !initialized)
|| (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. */
{
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
}
while (reconsider);
+ walk_namespaces (diagnose_inline_vars_for_namespace, /*data=*/0);
+
lower_var_init ();
generate_mangling_aliases ();
{
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);
}
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
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
+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
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'" }
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" }
# 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
--- /dev/null
+// { 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 ();
+}
--- /dev/null
+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;
--- /dev/null
+// { 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;
--- /dev/null
+// { 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;
--- /dev/null
+// { 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
// { 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