From: Jason Merrill Date: Thu, 13 Oct 2016 19:26:54 +0000 (-0400) Subject: Implement P0386R2 - C++17 inline variables X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=14a2c9aac04f013245e332b9e7ecb8c3a9f42a0a;p=gcc.git Implement P0386R2 - C++17 inline variables 2016-10-11 Jakub Jelinek * 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 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 6fdf0b96577..ae5a7109a81 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2016-10-13 Jakub Jelinek + + * dwarf2out.c (gen_member_die): Handle inline static data member + definitions. + 2016-10-13 Nathan Sidwell * gcov-io.c (gcov_open): Fix documentation. Simplify setting diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 285ef04e6f1..e4ba2de334d 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,7 @@ +2016-10-13 Jason Merrill + + * c-cppbuiltin.c (c_cpp_builtins): Add __cpp_inline_variables. + 2016-10-13 Thomas Preud'homme * c-cppbuiltin.c: Include memmodel.h. diff --git a/gcc/c-family/c-cppbuiltin.c b/gcc/c-family/c-cppbuiltin.c index 94af585eafe..06b5aa3ac65 100644 --- a/gcc/c-family/c-cppbuiltin.c +++ b/gcc/c-family/c-cppbuiltin.c @@ -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 diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index d792fb4e79a..5753ab10a9a 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,44 @@ +2016-10-13 Jakub Jelinek + Jason Merrill + + 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 + + * decl.c (mark_inline_variable): New. + 2016-10-13 Thomas Preud'homme * decl2.c: Include memmodel.h. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 88cae04e69b..f4a8985b351 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -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); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 62408931900..f761d0dfa92 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -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 *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 % 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 **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 % variable", object); - if (inlinep) - error ("%qD declared as an % variable", object); if (quals) error ("% and % 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 ("% 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) diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index ea9d379989d..e0fff1e81c5 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -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 (); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 28b1c987153..028025deb7a 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -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); } diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index a063ea34392..121da32dd4b 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -807,7 +807,7 @@ store_init_value (tree decl, tree init, vec** 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 diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index 4376751a529..541faf75f1f 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -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 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index a8c1f6163b2..5e31162e2c6 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,13 @@ +2016-10-13 Jakub Jelinek + + * 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 * gcc.target/arm/scd42-1.c: Skip if -mcpu incompatible with diff --git a/gcc/testsuite/g++.dg/concepts/decl-diagnose.C b/gcc/testsuite/g++.dg/concepts/decl-diagnose.C index 9829ba1ba69..65785b25fe9 100644 --- a/gcc/testsuite/g++.dg/concepts/decl-diagnose.C +++ b/gcc/testsuite/g++.dg/concepts/decl-diagnose.C @@ -16,6 +16,7 @@ struct X template 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'" } diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-ice10.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-ice10.C index 51612737847..381b8a4ea32 100644 --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-ice10.C +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-ice10.C @@ -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" } diff --git a/gcc/testsuite/g++.dg/cpp1z/feat-cxx1z.C b/gcc/testsuite/g++.dg/cpp1z/feat-cxx1z.C index eeeae45cd73..c86dbe2c911 100644 --- a/gcc/testsuite/g++.dg/cpp1z/feat-cxx1z.C +++ b/gcc/testsuite/g++.dg/cpp1z/feat-cxx1z.C @@ -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 diff --git a/gcc/testsuite/g++.dg/cpp1z/inline-var1.C b/gcc/testsuite/g++.dg/cpp1z/inline-var1.C new file mode 100644 index 00000000000..c4fdaf8384a --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/inline-var1.C @@ -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::var24; +int &ref25 = Y::var25; +int &ref26 = Y::var26; +int &ref27 = var27; +const int &ref28 = Y::var28; +const char &ref24a = Y::var24; +char &ref25a = Y::var25; +int &ref26a = Y::var26; +char &ref27a = var27; +const char &ref28a = Y::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::var24 != 6 + || Y::var25 != 7 + || Y::var26 != 8 + || var27 != 9 + || Y::var28 != 10 + || Y::var24 != 6 + || Y::var25 != 7 + || Y::var26 != 8 + || var27 != 9 + || Y::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 (); +} diff --git a/gcc/testsuite/g++.dg/cpp1z/inline-var1.h b/gcc/testsuite/g++.dg/cpp1z/inline-var1.h new file mode 100644 index 00000000000..675e71b0763 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/inline-var1.h @@ -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 +struct Y +{ + static constexpr T var24 = 6; + static inline T var25 = 7; + static inline int var26 = 8; + static constexpr T var28 = 10; +}; +template +const T Y::var24; +template +const T Y::var24; +template +inline T var27 = 9; diff --git a/gcc/testsuite/g++.dg/cpp1z/inline-var1a.C b/gcc/testsuite/g++.dg/cpp1z/inline-var1a.C new file mode 100644 index 00000000000..9b3da299837 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/inline-var1a.C @@ -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::var24; +int &alt25 = Y::var25; +int &alt26 = Y::var26; +int &alt27 = var27; +const int &alt28 = Y::var28; +const char &alt24a = Y::var24; +char &alt25a = Y::var25; +int &alt26a = Y::var26; +char &alt27a = var27; +const char &alt28a = Y::var28; diff --git a/gcc/testsuite/g++.dg/cpp1z/inline-var2.C b/gcc/testsuite/g++.dg/cpp1z/inline-var2.C new file mode 100644 index 00000000000..bfbbe1d6223 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/inline-var2.C @@ -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 +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 y; +A *ptr34 = &Y::var34; +B *ptr35 = &Y::var35; +C *ptr36 = &Y::var36; +template +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 Z::var37; // { dg-error "redefinition of" } +template +const int Z::var38; // { dg-error "redefinition of" } +const int &ref38 = Z<0>::var38; +template +int Z::var39; // { dg-error "redefinition of" } +template +const int Z::var40; // { dg-error "redefinition of" } +template +double Z::var41; // { dg-error "redefinition of" } +template +double const Z::var42; // { dg-error "redefinition of" } +template +const int Z::var43; // { dg-warning "redundant redeclaration of" "" { target c++1z } } +template // { dg-warning "redundant redeclaration of" "" { target c++1z } .+1 } +const int Z::var43; // { dg-error "redefinition of" "" { target c++14_down } } +Z<0> z; diff --git a/gcc/testsuite/g++.dg/cpp1z/inline-var3.C b/gcc/testsuite/g++.dg/cpp1z/inline-var3.C new file mode 100644 index 00000000000..7bee9dc30aa --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/inline-var3.C @@ -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 // { 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 // { 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 // { 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 // { 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 +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 diff --git a/gcc/testsuite/g++.old-deja/g++.brendan/misc6.C b/gcc/testsuite/g++.old-deja/g++.brendan/misc6.C index 93b241b9e04..c7d35b7f71e 100644 --- a/gcc/testsuite/g++.old-deja/g++.brendan/misc6.C +++ b/gcc/testsuite/g++.old-deja/g++.brendan/misc6.C @@ -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