PR c++/91360 - Implement C++20 P1143R2: constinit.
* c-common.c (c_common_reswords): Add constinit and __constinit. (keyword_is_decl_specifier): Handle RID_CONSTINIT. * c-common.h (enum rid): Add RID_CONSTINIT, RID_FIRST_CXX20, and RID_LAST_CXX20. (D_CXX20): Define. * c-cppbuiltin.c (c_cpp_builtins): Define __cpp_constinit. * c-format.c (cxx_keywords): Add "constinit". * c.opt (Wc++2a-compat, Wc++20-compat): New options. * cp-tree.h (TINFO_VAR_DECLARED_CONSTINIT): Define. (LOOKUP_CONSTINIT): Define. (enum cp_decl_spec): Add ds_constinit. * decl.c (check_tag_decl): Give an error for constinit in type declarations. (check_initializer): Also check LOOKUP_CONSTINIT. (cp_finish_decl): Add checking for a constinit declaration. Set TINFO_VAR_DECLARED_CONSTINIT. (grokdeclarator): Add checking for a declaration with the constinit specifier. * lex.c (init_reswords): Handle D_CXX20. * parser.c (cp_lexer_get_preprocessor_token): Pass a better location to warning_at. Warn about C++20 keywords. (cp_keyword_starts_decl_specifier_p): Handle RID_CONSTINIT. (cp_parser_diagnose_invalid_type_name): Add an inform about constinit. (cp_parser_decomposition_declaration): Maybe pass LOOKUP_CONSTINIT to cp_finish_decl. (cp_parser_decl_specifier_seq): Handle RID_CONSTINIT. (cp_parser_init_declarator): Maybe pass LOOKUP_CONSTINIT to cp_finish_decl. (set_and_check_decl_spec_loc): Add "constinit". * pt.c (tsubst_decl): Set TINFO_VAR_DECLARED_CONSTINIT. (instantiate_decl): Maybe pass LOOKUP_CONSTINIT to cp_finish_decl. * typeck2.c (store_init_value): If a constinit variable wasn't initialized using a constant initializer, give an error. * doc/invoke.texi: Document -Wc++20-compat. * g++.dg/cpp2a/constinit1.C: New test. * g++.dg/cpp2a/constinit2.C: New test. * g++.dg/cpp2a/constinit3.C: New test. * g++.dg/cpp2a/constinit4.C: New test. * g++.dg/cpp2a/constinit5.C: New test. * g++.dg/cpp2a/constinit6.C: New test. * g++.dg/cpp2a/constinit7.C: New test. * g++.dg/cpp2a/constinit8.C: New test. * g++.dg/cpp2a/constinit9.C: New test. * g++.dg/cpp2a/constinit10.C: New test. * g++.dg/cpp2a/constinit11.C: New test. * g++.dg/cpp2a/constinit12.C: New test. From-SVN: r275008
This commit is contained in:
parent
6e12721acd
commit
4742dbe718
@ -1,3 +1,8 @@
|
||||
2019-08-28 Marek Polacek <polacek@redhat.com>
|
||||
|
||||
PR c++/91360 - Implement C++20 P1143R2: constinit.
|
||||
* doc/invoke.texi: Document -Wc++20-compat.
|
||||
|
||||
2019-08-28 Martin Sebor <msebor@redhat.com>
|
||||
|
||||
PR tree-optimization/91457
|
||||
|
@ -1,3 +1,15 @@
|
||||
2019-08-28 Marek Polacek <polacek@redhat.com>
|
||||
|
||||
PR c++/91360 - Implement C++20 P1143R2: constinit.
|
||||
* c-common.c (c_common_reswords): Add constinit and __constinit.
|
||||
(keyword_is_decl_specifier): Handle RID_CONSTINIT.
|
||||
* c-common.h (enum rid): Add RID_CONSTINIT, RID_FIRST_CXX20, and
|
||||
RID_LAST_CXX20.
|
||||
(D_CXX20): Define.
|
||||
* c-cppbuiltin.c (c_cpp_builtins): Define __cpp_constinit.
|
||||
* c-format.c (cxx_keywords): Add "constinit".
|
||||
* c.opt (Wc++2a-compat, Wc++20-compat): New options.
|
||||
|
||||
2019-08-27 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
PR c++/91415
|
||||
|
@ -326,8 +326,9 @@ static bool nonnull_check_p (tree, unsigned HOST_WIDE_INT);
|
||||
C --std=c89: D_C99 | D_CXXONLY | D_OBJC | D_CXX_OBJC
|
||||
C --std=c99: D_CXXONLY | D_OBJC
|
||||
ObjC is like C except that D_OBJC and D_CXX_OBJC are not set
|
||||
C++ --std=c++98: D_CONLY | D_CXX11 | D_OBJC
|
||||
C++ --std=c++11: D_CONLY | D_OBJC
|
||||
C++ --std=c++98: D_CONLY | D_CXX11 | D_CXX20 | D_OBJC
|
||||
C++ --std=c++11: D_CONLY | D_CXX20 | D_OBJC
|
||||
C++ --std=c++2a: D_CONLY | D_OBJC
|
||||
ObjC++ is like C++ except that D_OBJC is not set
|
||||
|
||||
If -fno-asm is used, D_ASM is added to the mask. If
|
||||
@ -392,6 +393,7 @@ const struct c_common_resword c_common_reswords[] =
|
||||
{ "__complex__", RID_COMPLEX, 0 },
|
||||
{ "__const", RID_CONST, 0 },
|
||||
{ "__const__", RID_CONST, 0 },
|
||||
{ "__constinit", RID_CONSTINIT, D_CXXONLY },
|
||||
{ "__decltype", RID_DECLTYPE, D_CXXONLY },
|
||||
{ "__direct_bases", RID_DIRECT_BASES, D_CXXONLY },
|
||||
{ "__extension__", RID_EXTENSION, 0 },
|
||||
@ -462,6 +464,7 @@ const struct c_common_resword c_common_reswords[] =
|
||||
{ "class", RID_CLASS, D_CXX_OBJC | D_CXXWARN },
|
||||
{ "const", RID_CONST, 0 },
|
||||
{ "constexpr", RID_CONSTEXPR, D_CXXONLY | D_CXX11 | D_CXXWARN },
|
||||
{ "constinit", RID_CONSTINIT, D_CXXONLY | D_CXX20 | D_CXXWARN },
|
||||
{ "const_cast", RID_CONSTCAST, D_CXXONLY | D_CXXWARN },
|
||||
{ "continue", RID_CONTINUE, 0 },
|
||||
{ "decltype", RID_DECLTYPE, D_CXXONLY | D_CXX11 | D_CXXWARN },
|
||||
@ -7927,6 +7930,7 @@ keyword_is_decl_specifier (enum rid keyword)
|
||||
case RID_TYPEDEF:
|
||||
case RID_FRIEND:
|
||||
case RID_CONSTEXPR:
|
||||
case RID_CONSTINIT:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
@ -180,6 +180,9 @@ enum rid
|
||||
/* C++11 */
|
||||
RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, RID_STATIC_ASSERT,
|
||||
|
||||
/* C++20 */
|
||||
RID_CONSTINIT,
|
||||
|
||||
/* char8_t */
|
||||
RID_CHAR8,
|
||||
|
||||
@ -250,6 +253,8 @@ enum rid
|
||||
|
||||
RID_FIRST_CXX11 = RID_CONSTEXPR,
|
||||
RID_LAST_CXX11 = RID_STATIC_ASSERT,
|
||||
RID_FIRST_CXX20 = RID_CONSTINIT,
|
||||
RID_LAST_CXX20 = RID_CONSTINIT,
|
||||
RID_FIRST_AT = RID_AT_ENCODE,
|
||||
RID_LAST_AT = RID_AT_IMPLEMENTATION,
|
||||
RID_FIRST_PQ = RID_IN,
|
||||
@ -427,6 +432,7 @@ extern machine_mode c_default_pointer_mode;
|
||||
#define D_CXX_CONCEPTS 0x0400 /* In C++, only with concepts. */
|
||||
#define D_TRANSMEM 0X0800 /* C++ transactional memory TS. */
|
||||
#define D_CXX_CHAR8_T 0X1000 /* In C++, only with -fchar8_t. */
|
||||
#define D_CXX20 0x2000 /* In C++, C++20 only. */
|
||||
|
||||
#define D_CXX_CONCEPTS_FLAGS D_CXXONLY | D_CXX_CONCEPTS
|
||||
#define D_CXX_CHAR8_T_FLAGS D_CXXONLY | D_CXX_CHAR8_T
|
||||
|
@ -986,6 +986,7 @@ c_cpp_builtins (cpp_reader *pfile)
|
||||
{
|
||||
/* Set feature test macros for C++2a. */
|
||||
cpp_define (pfile, "__cpp_conditional_explicit=201806");
|
||||
cpp_define (pfile, "__cpp_constinit=201907");
|
||||
cpp_define (pfile, "__cpp_nontype_template_parameter_class=201806");
|
||||
cpp_define (pfile, "__cpp_impl_destroying_delete=201806");
|
||||
}
|
||||
|
@ -2958,6 +2958,7 @@ static const token_t cxx_keywords[] =
|
||||
NAME ("catch", NULL),
|
||||
NAME ("constexpr if", NULL),
|
||||
NAME ("constexpr", NULL),
|
||||
NAME ("constinit", NULL),
|
||||
NAME ("consteval", NULL),
|
||||
NAME ("decltype", NULL),
|
||||
NAME ("nullptr", NULL),
|
||||
|
@ -400,6 +400,13 @@ Wc++17-compat
|
||||
C++ ObjC++ Var(warn_cxx17_compat) Warning LangEnabledBy(C++ ObjC++,Wall)
|
||||
Warn about C++ constructs whose meaning differs between ISO C++ 2014 and ISO C++ 2017.
|
||||
|
||||
Wc++2a-compat
|
||||
C++ ObjC++ Warning Alias(Wc++20-compat) Undocumented
|
||||
|
||||
Wc++20-compat
|
||||
C++ ObjC++ Var(warn_cxx20_compat) Warning LangEnabledBy(C++ ObjC++,Wall)
|
||||
Warn about C++ constructs whose meaning differs between ISO C++ 2017 and ISO C++ 2020.
|
||||
|
||||
Wcast-function-type
|
||||
C ObjC C++ ObjC++ Var(warn_cast_function_type) Warning EnabledBy(Wextra)
|
||||
Warn about casts between incompatible function types.
|
||||
|
@ -1,3 +1,32 @@
|
||||
2019-08-28 Marek Polacek <polacek@redhat.com>
|
||||
|
||||
PR c++/91360 - Implement C++20 P1143R2: constinit.
|
||||
* cp-tree.h (TINFO_VAR_DECLARED_CONSTINIT): Define.
|
||||
(LOOKUP_CONSTINIT): Define.
|
||||
(enum cp_decl_spec): Add ds_constinit.
|
||||
* decl.c (check_tag_decl): Give an error for constinit in type
|
||||
declarations.
|
||||
(check_initializer): Also check LOOKUP_CONSTINIT.
|
||||
(cp_finish_decl): Add checking for a constinit declaration. Set
|
||||
TINFO_VAR_DECLARED_CONSTINIT.
|
||||
(grokdeclarator): Add checking for a declaration with the constinit
|
||||
specifier.
|
||||
* lex.c (init_reswords): Handle D_CXX20.
|
||||
* parser.c (cp_lexer_get_preprocessor_token): Pass a better location
|
||||
to warning_at. Warn about C++20 keywords.
|
||||
(cp_keyword_starts_decl_specifier_p): Handle RID_CONSTINIT.
|
||||
(cp_parser_diagnose_invalid_type_name): Add an inform about constinit.
|
||||
(cp_parser_decomposition_declaration): Maybe pass LOOKUP_CONSTINIT to
|
||||
cp_finish_decl.
|
||||
(cp_parser_decl_specifier_seq): Handle RID_CONSTINIT.
|
||||
(cp_parser_init_declarator): Maybe pass LOOKUP_CONSTINIT to
|
||||
cp_finish_decl.
|
||||
(set_and_check_decl_spec_loc): Add "constinit".
|
||||
* pt.c (tsubst_decl): Set TINFO_VAR_DECLARED_CONSTINIT.
|
||||
(instantiate_decl): Maybe pass LOOKUP_CONSTINIT to cp_finish_decl.
|
||||
* typeck2.c (store_init_value): If a constinit variable wasn't
|
||||
initialized using a constant initializer, give an error.
|
||||
|
||||
2019-08-28 Nathan Sidwell <nathan@acm.org>
|
||||
|
||||
PR c++/90613
|
||||
|
@ -443,6 +443,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
|
||||
SWITCH_STMT_NO_BREAK_P (in SWITCH_STMT)
|
||||
LAMBDA_EXPR_CAPTURE_OPTIMIZED (in LAMBDA_EXPR)
|
||||
IMPLICIT_CONV_EXPR_BRACED_INIT (in IMPLICIT_CONV_EXPR)
|
||||
TINFO_VAR_DECLARED_CONSTINIT (in TEMPLATE_INFO)
|
||||
3: (TREE_REFERENCE_EXPR) (in NON_LVALUE_EXPR) (commented-out).
|
||||
ICS_BAD_FLAG (in _CONV)
|
||||
FN_TRY_BLOCK_P (in TRY_BLOCK)
|
||||
@ -1435,6 +1436,11 @@ typedef struct qualified_typedef_usage_s qualified_typedef_usage_t;
|
||||
#define TINFO_USED_TEMPLATE_ID(NODE) \
|
||||
(TREE_LANG_FLAG_1 (TEMPLATE_INFO_CHECK (NODE)))
|
||||
|
||||
/* Non-zero if this variable template specialization was declared with the
|
||||
`constinit' specifier. */
|
||||
#define TINFO_VAR_DECLARED_CONSTINIT(NODE) \
|
||||
(TREE_LANG_FLAG_2 (TEMPLATE_INFO_CHECK (NODE)))
|
||||
|
||||
struct GTY(()) tree_template_info {
|
||||
struct tree_base base;
|
||||
tree tmpl;
|
||||
@ -5502,6 +5508,8 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, TYPENAME_FLAG };
|
||||
#define LOOKUP_DELEGATING_CONS (LOOKUP_NO_NON_INTEGRAL << 1)
|
||||
/* Allow initialization of a flexible array members. */
|
||||
#define LOOKUP_ALLOW_FLEXARRAY_INIT (LOOKUP_DELEGATING_CONS << 1)
|
||||
/* Require constant initialization of a non-constant variable. */
|
||||
#define LOOKUP_CONSTINIT (LOOKUP_ALLOW_FLEXARRAY_INIT << 1)
|
||||
|
||||
#define LOOKUP_NAMESPACES_ONLY(F) \
|
||||
(((F) & LOOKUP_PREFER_NAMESPACES) && !((F) & LOOKUP_PREFER_TYPES))
|
||||
@ -5815,6 +5823,7 @@ enum cp_decl_spec {
|
||||
ds_alias,
|
||||
ds_constexpr,
|
||||
ds_complex,
|
||||
ds_constinit,
|
||||
ds_thread,
|
||||
ds_type_spec,
|
||||
ds_redefined_builtin_type_spec,
|
||||
|
@ -4962,6 +4962,9 @@ check_tag_decl (cp_decl_specifier_seq *declspecs,
|
||||
else if (decl_spec_seq_has_spec_p (declspecs, ds_constexpr))
|
||||
error_at (declspecs->locations[ds_constexpr],
|
||||
"%<constexpr%> cannot be used for type declarations");
|
||||
else if (decl_spec_seq_has_spec_p (declspecs, ds_constinit))
|
||||
error_at (declspecs->locations[ds_constinit],
|
||||
"%<constinit%> cannot be used for type declarations");
|
||||
}
|
||||
|
||||
if (declspecs->attributes && warn_attributes && declared_type)
|
||||
@ -6595,11 +6598,12 @@ check_initializer (tree decl, tree init, int flags, vec<tree, va_gc> **cleanups)
|
||||
about aggregate initialization of non-aggregate classes. */
|
||||
flags |= LOOKUP_ALREADY_DIGESTED;
|
||||
}
|
||||
else if (DECL_DECLARED_CONSTEXPR_P (decl))
|
||||
else if (DECL_DECLARED_CONSTEXPR_P (decl)
|
||||
|| (flags & LOOKUP_CONSTINIT))
|
||||
{
|
||||
/* Declared constexpr, but no suitable initializer; massage
|
||||
init appropriately so we can pass it into store_init_value
|
||||
for the error. */
|
||||
/* Declared constexpr or constinit, but no suitable initializer;
|
||||
massage init appropriately so we can pass it into
|
||||
store_init_value for the error. */
|
||||
if (CLASS_TYPE_P (type)
|
||||
&& (!init || TREE_CODE (init) == TREE_LIST))
|
||||
{
|
||||
@ -7162,6 +7166,10 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
|
||||
DECL_INITIAL (decl) = NULL_TREE;
|
||||
}
|
||||
|
||||
/* Handle `constinit' on variable templates. */
|
||||
if (flags & LOOKUP_CONSTINIT)
|
||||
TINFO_VAR_DECLARED_CONSTINIT (DECL_TEMPLATE_INFO (decl)) = true;
|
||||
|
||||
/* Generally, initializers in templates are expanded when the
|
||||
template is instantiated. But, if DECL is a variable constant
|
||||
then it can be used in future constant expressions, so its value
|
||||
@ -7253,6 +7261,18 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
|
||||
|
||||
if (VAR_P (decl))
|
||||
{
|
||||
duration_kind dk = decl_storage_duration (decl);
|
||||
/* [dcl.constinit]/1 "The constinit specifier shall be applied
|
||||
only to a declaration of a variable with static or thread storage
|
||||
duration." */
|
||||
if ((flags & LOOKUP_CONSTINIT)
|
||||
&& !(dk == dk_thread || dk == dk_static))
|
||||
{
|
||||
error ("%<constinit%> can only be applied to a variable with static "
|
||||
"or thread storage duration");
|
||||
return;
|
||||
}
|
||||
|
||||
/* If this is a local variable that will need a mangled name,
|
||||
register it now. We must do this before processing the
|
||||
initializer for the variable, since the initialization might
|
||||
@ -10477,6 +10497,7 @@ grokdeclarator (const cp_declarator *declarator,
|
||||
bool template_parm_flag = false;
|
||||
bool typedef_p = decl_spec_seq_has_spec_p (declspecs, ds_typedef);
|
||||
bool constexpr_p = decl_spec_seq_has_spec_p (declspecs, ds_constexpr);
|
||||
bool constinit_p = decl_spec_seq_has_spec_p (declspecs, ds_constinit);
|
||||
bool late_return_type_p = false;
|
||||
bool array_parameter_p = false;
|
||||
location_t saved_loc = input_location;
|
||||
@ -10763,6 +10784,24 @@ grokdeclarator (const cp_declarator *declarator,
|
||||
return error_mark_node;
|
||||
}
|
||||
|
||||
if (constinit_p && typedef_p)
|
||||
{
|
||||
error_at (declspecs->locations[ds_constinit],
|
||||
"%<constinit%> cannot appear in a typedef declaration");
|
||||
return error_mark_node;
|
||||
}
|
||||
|
||||
/* [dcl.spec]/2 "At most one of the constexpr, consteval, and constinit
|
||||
keywords shall appear in a decl-specifier-seq." */
|
||||
if (constinit_p && constexpr_p)
|
||||
{
|
||||
error_at (min_location (declspecs->locations[ds_constinit],
|
||||
declspecs->locations[ds_constexpr]),
|
||||
"can use at most one of the %<constinit%> and %<constexpr%> "
|
||||
"specifiers");
|
||||
return error_mark_node;
|
||||
}
|
||||
|
||||
/* If there were multiple types specified in the decl-specifier-seq,
|
||||
issue an error message. */
|
||||
if (declspecs->multiple_types_p)
|
||||
@ -11155,6 +11194,12 @@ grokdeclarator (const cp_declarator *declarator,
|
||||
"a parameter cannot be declared %<constexpr%>");
|
||||
constexpr_p = 0;
|
||||
}
|
||||
else if (constinit_p)
|
||||
{
|
||||
error_at (declspecs->locations[ds_constinit],
|
||||
"a parameter cannot be declared %<constinit%>");
|
||||
constexpr_p = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Give error if `virtual' is used outside of class declaration. */
|
||||
@ -11597,6 +11642,13 @@ grokdeclarator (const cp_declarator *declarator,
|
||||
"an array", name);
|
||||
return error_mark_node;
|
||||
}
|
||||
if (constinit_p)
|
||||
{
|
||||
error_at (declspecs->locations[ds_constinit],
|
||||
"%<constinit%> on function return type is not "
|
||||
"allowed");
|
||||
return error_mark_node;
|
||||
}
|
||||
|
||||
if (ctype == NULL_TREE
|
||||
&& decl_context == FIELD
|
||||
@ -12794,10 +12846,17 @@ grokdeclarator (const cp_declarator *declarator,
|
||||
else if (constexpr_p)
|
||||
{
|
||||
error_at (declspecs->locations[ds_constexpr],
|
||||
"non-static data member %qE declared %<constexpr%>",
|
||||
unqualified_id);
|
||||
"non-static data member %qE declared "
|
||||
"%<constexpr%>", unqualified_id);
|
||||
constexpr_p = false;
|
||||
}
|
||||
else if (constinit_p)
|
||||
{
|
||||
error_at (declspecs->locations[ds_constinit],
|
||||
"non-static data member %qE declared "
|
||||
"%<constinit%>", unqualified_id);
|
||||
constinit_p = false;
|
||||
}
|
||||
decl = build_decl (id_loc, FIELD_DECL, unqualified_id, type);
|
||||
DECL_NONADDRESSABLE_P (decl) = bitfield;
|
||||
if (bitfield && !unqualified_id)
|
||||
|
@ -229,6 +229,8 @@ init_reswords (void)
|
||||
|
||||
if (cxx_dialect < cxx11)
|
||||
mask |= D_CXX11;
|
||||
if (cxx_dialect < cxx2a)
|
||||
mask |= D_CXX20;
|
||||
if (!flag_concepts)
|
||||
mask |= D_CXX_CONCEPTS;
|
||||
if (!flag_tm)
|
||||
|
@ -834,14 +834,28 @@ cp_lexer_get_preprocessor_token (cp_lexer *lexer, cp_token *token)
|
||||
{
|
||||
/* Warn about the C++0x keyword (but still treat it as
|
||||
an identifier). */
|
||||
warning (OPT_Wc__11_compat,
|
||||
"identifier %qE is a keyword in C++11",
|
||||
token->u.value);
|
||||
warning_at (token->location, OPT_Wc__11_compat,
|
||||
"identifier %qE is a keyword in C++11",
|
||||
token->u.value);
|
||||
|
||||
/* Clear out the C_RID_CODE so we don't warn about this
|
||||
particular identifier-turned-keyword again. */
|
||||
C_SET_RID_CODE (token->u.value, RID_MAX);
|
||||
}
|
||||
if (warn_cxx20_compat
|
||||
&& C_RID_CODE (token->u.value) >= RID_FIRST_CXX20
|
||||
&& C_RID_CODE (token->u.value) <= RID_LAST_CXX20)
|
||||
{
|
||||
/* Warn about the C++20 keyword (but still treat it as
|
||||
an identifier). */
|
||||
warning_at (token->location, OPT_Wc__20_compat,
|
||||
"identifier %qE is a keyword in C++20",
|
||||
token->u.value);
|
||||
|
||||
/* Clear out the C_RID_CODE so we don't warn about this
|
||||
particular identifier-turned-keyword again. */
|
||||
C_SET_RID_CODE (token->u.value, RID_MAX);
|
||||
}
|
||||
|
||||
token->keyword = RID_MAX;
|
||||
}
|
||||
@ -986,6 +1000,7 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
|
||||
case RID_DECLTYPE:
|
||||
case RID_UNDERLYING_TYPE:
|
||||
case RID_CONSTEXPR:
|
||||
case RID_CONSTINIT:
|
||||
return true;
|
||||
|
||||
default:
|
||||
@ -3353,6 +3368,9 @@ cp_parser_diagnose_invalid_type_name (cp_parser *parser, tree id,
|
||||
&& id_equal (id, "thread_local"))
|
||||
inform (location, "C++11 %<thread_local%> only available with "
|
||||
"%<-std=c++11%> or %<-std=gnu++11%>");
|
||||
else if (cxx_dialect < cxx2a && id == ridpointers[(int)RID_CONSTINIT])
|
||||
inform (location, "C++20 %<constinit%> only available with "
|
||||
"%<-std=c++2a%> or %<-std=gnu++2a%>");
|
||||
else if (!flag_concepts && id == ridpointers[(int)RID_CONCEPT])
|
||||
inform (location, "%<concept%> only available with %<-fconcepts%>");
|
||||
else if (processing_template_decl && current_class_type
|
||||
@ -13839,9 +13857,12 @@ cp_parser_decomposition_declaration (cp_parser *parser,
|
||||
|
||||
if (decl != error_mark_node)
|
||||
{
|
||||
int flags = (decl_spec_seq_has_spec_p (decl_specifiers, ds_constinit)
|
||||
? LOOKUP_CONSTINIT : 0);
|
||||
cp_maybe_mangle_decomp (decl, prev, v.length ());
|
||||
cp_finish_decl (decl, initializer, non_constant_p, NULL_TREE,
|
||||
is_direct_init ? LOOKUP_NORMAL : LOOKUP_IMPLICIT);
|
||||
(is_direct_init ? LOOKUP_NORMAL : LOOKUP_IMPLICIT)
|
||||
| flags);
|
||||
cp_finish_decomp (decl, prev, v.length ());
|
||||
}
|
||||
}
|
||||
@ -13993,7 +14014,8 @@ cp_parser_decl_specifier_seq (cp_parser* parser,
|
||||
{
|
||||
/* decl-specifier:
|
||||
friend
|
||||
constexpr */
|
||||
constexpr
|
||||
constinit */
|
||||
case RID_FRIEND:
|
||||
if (!at_class_scope_p ())
|
||||
{
|
||||
@ -14015,6 +14037,11 @@ cp_parser_decl_specifier_seq (cp_parser* parser,
|
||||
cp_lexer_consume_token (parser->lexer);
|
||||
break;
|
||||
|
||||
case RID_CONSTINIT:
|
||||
ds = ds_constinit;
|
||||
cp_lexer_consume_token (parser->lexer);
|
||||
break;
|
||||
|
||||
case RID_CONCEPT:
|
||||
ds = ds_concept;
|
||||
cp_lexer_consume_token (parser->lexer);
|
||||
@ -20532,6 +20559,8 @@ cp_parser_init_declarator (cp_parser* parser,
|
||||
declarations. */
|
||||
if (!member_p && decl && decl != error_mark_node && !range_for_decl_p)
|
||||
{
|
||||
int cf = (decl_spec_seq_has_spec_p (decl_specifiers, ds_constinit)
|
||||
? LOOKUP_CONSTINIT : 0);
|
||||
cp_finish_decl (decl,
|
||||
initializer, !is_non_constant_init,
|
||||
asm_specification,
|
||||
@ -20540,7 +20569,7 @@ cp_parser_init_declarator (cp_parser* parser,
|
||||
`explicit' constructor is OK. Otherwise, an
|
||||
`explicit' constructor cannot be used. */
|
||||
((is_direct_init || !is_initialized)
|
||||
? LOOKUP_NORMAL : LOOKUP_IMPLICIT));
|
||||
? LOOKUP_NORMAL : LOOKUP_IMPLICIT) | cf);
|
||||
}
|
||||
else if ((cxx_dialect != cxx98) && friend_p
|
||||
&& decl && TREE_CODE (decl) == FUNCTION_DECL)
|
||||
@ -29470,7 +29499,8 @@ set_and_check_decl_spec_loc (cp_decl_specifier_seq *decl_specs,
|
||||
"typedef",
|
||||
"using",
|
||||
"constexpr",
|
||||
"__complex"
|
||||
"__complex",
|
||||
"constinit"
|
||||
};
|
||||
gcc_rich_location richloc (location);
|
||||
richloc.add_fixit_remove ();
|
||||
|
@ -13955,6 +13955,10 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
|
||||
|
||||
DECL_TEMPLATE_INFO (r) = build_template_info (tmpl, argvec);
|
||||
SET_DECL_IMPLICIT_INSTANTIATION (r);
|
||||
/* Remember whether we require constant initialization of
|
||||
a non-constant template variable. */
|
||||
TINFO_VAR_DECLARED_CONSTINIT (DECL_TEMPLATE_INFO (r))
|
||||
= TINFO_VAR_DECLARED_CONSTINIT (DECL_TEMPLATE_INFO (t));
|
||||
if (!error_operand_p (r) || (complain & tf_error))
|
||||
register_specialization (r, gen_tmpl, argvec, false, hash);
|
||||
}
|
||||
@ -24744,7 +24748,9 @@ instantiate_decl (tree d, bool defer_ok, bool expl_inst_class_mem_p)
|
||||
push_nested_class (DECL_CONTEXT (d));
|
||||
|
||||
const_init = DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (code_pattern);
|
||||
cp_finish_decl (d, init, const_init, NULL_TREE, 0);
|
||||
int flags = (TINFO_VAR_DECLARED_CONSTINIT (DECL_TEMPLATE_INFO (d))
|
||||
? LOOKUP_CONSTINIT : 0);
|
||||
cp_finish_decl (d, init, const_init, NULL_TREE, flags);
|
||||
|
||||
if (enter_context)
|
||||
pop_nested_class ();
|
||||
|
@ -885,7 +885,22 @@ store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags)
|
||||
if (!TYPE_REF_P (type))
|
||||
TREE_CONSTANT (decl) = const_init && decl_maybe_constant_var_p (decl);
|
||||
if (!const_init)
|
||||
value = oldval;
|
||||
{
|
||||
/* [dcl.constinit]/2 "If a variable declared with the constinit
|
||||
specifier has dynamic initialization, the program is
|
||||
ill-formed." */
|
||||
if (flags & LOOKUP_CONSTINIT)
|
||||
{
|
||||
error_at (location_of (decl),
|
||||
"%<constinit%> variable %qD does not have a constant "
|
||||
"initializer", decl);
|
||||
if (require_constant_expression (value))
|
||||
cxx_constant_init (value, decl);
|
||||
value = error_mark_node;
|
||||
}
|
||||
else
|
||||
value = oldval;
|
||||
}
|
||||
}
|
||||
value = cp_fully_fold_init (value);
|
||||
|
||||
|
@ -295,6 +295,7 @@ Objective-C and Objective-C++ Dialects}.
|
||||
-Wno-builtin-declaration-mismatch @gol
|
||||
-Wno-builtin-macro-redefined -Wc90-c99-compat -Wc99-c11-compat @gol
|
||||
-Wc++-compat -Wc++11-compat -Wc++14-compat -Wc++17-compat @gol
|
||||
-Wc++20-compat @gol
|
||||
-Wcast-align -Wcast-align=strict -Wcast-function-type -Wcast-qual @gol
|
||||
-Wchar-subscripts -Wcatch-value -Wcatch-value=@var{n} @gol
|
||||
-Wclobbered -Wcomment -Wconditionally-supported @gol
|
||||
@ -6792,6 +6793,12 @@ and ISO C++ 2014. This warning is enabled by @option{-Wall}.
|
||||
Warn about C++ constructs whose meaning differs between ISO C++ 2014
|
||||
and ISO C++ 2017. This warning is enabled by @option{-Wall}.
|
||||
|
||||
@item -Wc++20-compat @r{(C++ and Objective-C++ only)}
|
||||
@opindex Wc++20-compat
|
||||
@opindex Wno-c++20-compat
|
||||
Warn about C++ constructs whose meaning differs between ISO C++ 2017
|
||||
and ISO C++ 2020. This warning is enabled by @option{-Wall}.
|
||||
|
||||
@item -Wcast-qual
|
||||
@opindex Wcast-qual
|
||||
@opindex Wno-cast-qual
|
||||
|
@ -1,3 +1,19 @@
|
||||
2019-08-28 Marek Polacek <polacek@redhat.com>
|
||||
|
||||
PR c++/91360 - Implement C++20 P1143R2: constinit.
|
||||
* g++.dg/cpp2a/constinit1.C: New test.
|
||||
* g++.dg/cpp2a/constinit2.C: New test.
|
||||
* g++.dg/cpp2a/constinit3.C: New test.
|
||||
* g++.dg/cpp2a/constinit4.C: New test.
|
||||
* g++.dg/cpp2a/constinit5.C: New test.
|
||||
* g++.dg/cpp2a/constinit6.C: New test.
|
||||
* g++.dg/cpp2a/constinit7.C: New test.
|
||||
* g++.dg/cpp2a/constinit8.C: New test.
|
||||
* g++.dg/cpp2a/constinit9.C: New test.
|
||||
* g++.dg/cpp2a/constinit10.C: New test.
|
||||
* g++.dg/cpp2a/constinit11.C: New test.
|
||||
* g++.dg/cpp2a/constinit12.C: New test.
|
||||
|
||||
2019-08-28 Steven G. Kargl <kargl@gcc.gnu.org>
|
||||
|
||||
PR fortran/91565
|
||||
|
38
gcc/testsuite/g++.dg/cpp2a/constinit1.C
Normal file
38
gcc/testsuite/g++.dg/cpp2a/constinit1.C
Normal file
@ -0,0 +1,38 @@
|
||||
// PR c++/91360 - Implement C++20 P1143R2: constinit
|
||||
// { dg-do compile { target c++2a } }
|
||||
// Test basic usage of 'constinit'.
|
||||
|
||||
const char *g() { return "dynamic init"; }
|
||||
constexpr const char *f(bool p) { return p ? "constant init" : g(); } // { dg-error "call to non-.constexpr. function" }
|
||||
|
||||
constinit const char *c = f(true);
|
||||
constinit const char *d = f(false); // { dg-error "variable .d. does not have a constant initializer" }
|
||||
// { dg-message "in .constexpr. expansion of" "" { target *-*-* } .-1 }
|
||||
static constinit const char *e = f(true);
|
||||
|
||||
constexpr int foo(int x) { return x; }
|
||||
constinit int i = foo(42);
|
||||
constinit int j // { dg-error "variable .j. does not have a constant initializer" }
|
||||
= foo(i); // { dg-error "not usable in a constant expression" }
|
||||
|
||||
int y = 42;
|
||||
constinit int x // { dg-error "variable .x. does not have a constant initializer" }
|
||||
= y; // { dg-error "not usable in a constant expression" }
|
||||
|
||||
constinit int z;
|
||||
const constinit unsigned cst = 1u;
|
||||
|
||||
void
|
||||
fn ()
|
||||
{
|
||||
static constinit int m = foo(42);
|
||||
static constinit int n // { dg-error "variable .n. does not have a constant initializer" }
|
||||
= foo(m); // { dg-error "not usable in a constant expression" }
|
||||
|
||||
// Make sure we can still modify constinit variables.
|
||||
c = "foo";
|
||||
i = 10;
|
||||
m = 90;
|
||||
// ... unless they're 'const'.
|
||||
cst *= 2; // { dg-error "assignment of read-only variable" }
|
||||
}
|
26
gcc/testsuite/g++.dg/cpp2a/constinit10.C
Normal file
26
gcc/testsuite/g++.dg/cpp2a/constinit10.C
Normal file
@ -0,0 +1,26 @@
|
||||
// PR c++/91360 - Implement C++20 P1143R2: constinit
|
||||
// { dg-do compile { target c++2a } }
|
||||
// From PR83428.
|
||||
|
||||
struct S1
|
||||
{
|
||||
constexpr S1 ();
|
||||
int m_i;
|
||||
};
|
||||
|
||||
struct alignas(64) S2
|
||||
{
|
||||
constexpr S2 ()
|
||||
: m_tabS1()
|
||||
{}
|
||||
|
||||
S1 m_tabS1[7];
|
||||
};
|
||||
|
||||
constinit S2 objX; // { dg-error ".constinit. variable .objX. does not have a constant initializer" }
|
||||
// { dg-error "used before its definition" "" { target *-*-* } .-1 }
|
||||
// // { dg-message "in .constexpr. expansion of" "" { target *-*-* } .-2 }
|
||||
|
||||
constexpr S1::S1 ()
|
||||
: m_i(14)
|
||||
{}
|
79
gcc/testsuite/g++.dg/cpp2a/constinit11.C
Normal file
79
gcc/testsuite/g++.dg/cpp2a/constinit11.C
Normal file
@ -0,0 +1,79 @@
|
||||
// PR c++/91360 - Implement C++20 P1143R2: constinit
|
||||
// { dg-do compile { target c++2a } }
|
||||
|
||||
int foo ();
|
||||
constexpr int constfoo () { return 42; }
|
||||
int gl = 42;
|
||||
|
||||
struct nonliteral {
|
||||
int m;
|
||||
nonliteral() : m() { }
|
||||
nonliteral(int n) : m(n) { }
|
||||
~nonliteral() {}
|
||||
};
|
||||
|
||||
struct literal {
|
||||
int m;
|
||||
constexpr literal() : m() { }
|
||||
constexpr literal(int n) : m(n) { }
|
||||
};
|
||||
|
||||
struct pod {
|
||||
int m;
|
||||
};
|
||||
|
||||
struct S {
|
||||
static constinit pod p;
|
||||
static constinit pod pc;
|
||||
static const constinit nonliteral n;
|
||||
};
|
||||
|
||||
struct W {
|
||||
int w = 42;
|
||||
};
|
||||
|
||||
constinit W w;
|
||||
|
||||
constinit const int &r1 = gl;
|
||||
constinit thread_local const int &r2 = gl;
|
||||
constinit const int &r3 // { dg-error "variable .r3. does not have a constant initializer" }
|
||||
= foo (); // { dg-error "call to non-.constexpr. function" }
|
||||
constinit const literal &r4 = 42;
|
||||
constinit const nonliteral &r5 // { dg-error "variable .r5. does not have a constant initializer" }
|
||||
= 42; // { dg-error "call to non-.constexpr. function" }
|
||||
constinit const int &r6 = nonliteral(2).m; // { dg-error "variable .r6. does not have a constant initializer|call to non-.constexpr. function" }
|
||||
|
||||
constinit pod p1;
|
||||
constinit pod p2 = { 42 };
|
||||
constinit pod p3 = { constfoo() };
|
||||
constinit pod p4 = { foo() }; // { dg-error "variable .p4. does not have a constant initializer|call to non-.constexpr. function" }
|
||||
|
||||
constexpr literal lit;
|
||||
constinit literal l1 = lit;
|
||||
constinit literal l2 = 42;
|
||||
constinit literal l3 = constfoo();
|
||||
constinit literal l4 = foo(); // { dg-error "variable .l4. does not have a constant initializer|call to non-.constexpr. function" }
|
||||
constinit literal l5 = {};
|
||||
constinit literal l6{};
|
||||
constinit thread_local literal l7 = lit;
|
||||
constinit thread_local literal l8 = 42;
|
||||
constinit thread_local literal l9 = constfoo();
|
||||
constinit thread_local literal l10 = foo(); // { dg-error "variable .l10. does not have a constant initializer|call to non-.constexpr. function" }
|
||||
constinit thread_local literal l11{};
|
||||
|
||||
pod S::p;
|
||||
constinit pod S::pc(S::p); // { dg-error "variable .S::pc. does not have a constant initializer|not usable" }
|
||||
|
||||
constinit const nonliteral S::n(42); // { dg-error "variable .S::n. does not have a constant initializer|call to non-.constexpr. function" }
|
||||
constinit int n1 = nonliteral{42}.m; // { dg-error "variable .n1. does not have a constant initializer|temporary of non-literal type" }
|
||||
constinit int n2 = literal{42}.m;
|
||||
|
||||
void
|
||||
fn1 ()
|
||||
{
|
||||
const int c = 42;
|
||||
static constinit const int &l // { dg-error "variable .l. does not have a constant initializer" }
|
||||
= c; // { dg-error "not a constant" }
|
||||
static const int &l2 = 10;
|
||||
static const int &l3 = gl;
|
||||
}
|
14
gcc/testsuite/g++.dg/cpp2a/constinit12.C
Normal file
14
gcc/testsuite/g++.dg/cpp2a/constinit12.C
Normal file
@ -0,0 +1,14 @@
|
||||
// PR c++/91360 - Implement C++20 P1143R2: constinit
|
||||
// { dg-do compile { target c++2a } }
|
||||
|
||||
struct S {
|
||||
S(int) { }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct U {
|
||||
T m;
|
||||
constexpr U(int i) : m(i) { } // { dg-error "call to non-.constexpr. function" }
|
||||
};
|
||||
|
||||
constinit U<S> u(42); // { dg-error "does not have a constant initializer|called in a constant expression" }
|
14
gcc/testsuite/g++.dg/cpp2a/constinit2.C
Normal file
14
gcc/testsuite/g++.dg/cpp2a/constinit2.C
Normal file
@ -0,0 +1,14 @@
|
||||
// PR c++/91360 - Implement C++20 P1143R2: constinit
|
||||
// { dg-do compile { target c++11 } }
|
||||
// Test that 'constinit' isn't recognized pre-C++2a, but '__constinit' is.
|
||||
|
||||
constinit int g = 42; // { dg-error ".constinit. does not name a type" "" { target c++17_down } }
|
||||
__constinit int g2 = 42;
|
||||
static __constinit int g3 = 42;
|
||||
|
||||
void
|
||||
fn ()
|
||||
{
|
||||
static constinit int x = 69; // { dg-error ".constinit. does not name a type" "" { target c++17_down } }
|
||||
static __constinit int x2 = 69;
|
||||
}
|
58
gcc/testsuite/g++.dg/cpp2a/constinit3.C
Normal file
58
gcc/testsuite/g++.dg/cpp2a/constinit3.C
Normal file
@ -0,0 +1,58 @@
|
||||
// PR c++/91360 - Implement C++20 P1143R2: constinit
|
||||
// { dg-do compile { target c++2a } }
|
||||
|
||||
constinit constinit int v1; // { dg-error "duplicate .constinit." }
|
||||
constexpr constinit int v2 = 1; // { dg-error "can use at most one of the .constinit. and .constexpr. specifiers" }
|
||||
constinit constexpr int v3 = 1; // { dg-error "an use at most one of the .constinit. and .constexpr. specifiers" }
|
||||
|
||||
extern static constinit int v4; // { dg-error "conflicting specifiers" }
|
||||
extern thread_local constinit int v5;
|
||||
extern constinit int v6;
|
||||
|
||||
constinit typedef int T; // { dg-error ".constinit. cannot appear in a typedef declaration" }
|
||||
|
||||
struct S2 {
|
||||
constinit int m1; // { dg-error "non-static data member .m1. declared .constinit." }
|
||||
constinit unsigned int b : 32; // { dg-error " non-static data member .b. declared .constinit." }
|
||||
};
|
||||
|
||||
struct S3 {
|
||||
constinit S3() {} // { dg-error ".constinit. on function return type is not allowed" }
|
||||
constinit ~S3() {} // { dg-error ".constinit. on function return type is not allowed" }
|
||||
};
|
||||
|
||||
constinit struct S4 { // { dg-error ".constinit. cannot be used for type declarations" }
|
||||
};
|
||||
|
||||
template<constinit int I> // { dg-error "a parameter cannot be declared .constinit." }
|
||||
struct X { };
|
||||
|
||||
int
|
||||
fn1 ()
|
||||
{
|
||||
// Not static storage
|
||||
constinit int a1 = 42; // { dg-error ".constinit. can only be applied to a variable with static or thread storage" }
|
||||
constinit int a2 = 42; // { dg-error ".constinit. can only be applied to a variable with static or thread storage" }
|
||||
extern constinit int e1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
constinit int // { dg-error ".constinit. on function return type is not allowed" }
|
||||
fn3 ()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
fn2 (int i, constinit int p) // { dg-error "a parameter cannot be declared .constinit." }
|
||||
{
|
||||
constinit auto l = [i](){ return i; }; // { dg-error ".constinit. can only be applied to a variable with static or thread storage" }
|
||||
}
|
||||
|
||||
struct B { int d; };
|
||||
|
||||
void
|
||||
fn3 (B b)
|
||||
{
|
||||
constinit auto [ a ] = b; // { dg-error ".constinit. can only be applied to a variable with static or thread storage" }
|
||||
}
|
16
gcc/testsuite/g++.dg/cpp2a/constinit4.C
Normal file
16
gcc/testsuite/g++.dg/cpp2a/constinit4.C
Normal file
@ -0,0 +1,16 @@
|
||||
// PR c++/91360 - Implement C++20 P1143R2: constinit
|
||||
// { dg-do compile { target c++2a } }
|
||||
|
||||
struct S { };
|
||||
constinit extern S s;
|
||||
constinit S s2 = { };
|
||||
|
||||
struct T {
|
||||
int i;
|
||||
};
|
||||
|
||||
constinit T t;
|
||||
struct U : T {
|
||||
int j;
|
||||
};
|
||||
constinit U u;
|
27
gcc/testsuite/g++.dg/cpp2a/constinit5.C
Normal file
27
gcc/testsuite/g++.dg/cpp2a/constinit5.C
Normal file
@ -0,0 +1,27 @@
|
||||
// PR c++/91360 - Implement C++20 P1143R2: constinit
|
||||
// { dg-do compile { target c++2a } }
|
||||
// Check that we preserve DECL_DECLARED_CONSTINIT_P in duplicate_decls.
|
||||
|
||||
int gl = 42;
|
||||
|
||||
struct S {
|
||||
constinit static int m;
|
||||
constinit static int n;
|
||||
constinit static const int &r1;
|
||||
constinit static const int &r2;
|
||||
};
|
||||
|
||||
int S::m = 42;
|
||||
int nonconst;
|
||||
constinit int S::n = nonconst; // { dg-error "variable .S::n. does not have a constant initializer" }
|
||||
// { dg-error "not usable in a constant expression" "" { target *-*-* } .-1 }
|
||||
|
||||
const int &S::r1 = gl;
|
||||
const int &S::r2 = 42;
|
||||
|
||||
struct T {
|
||||
constinit static thread_local const int &r1;
|
||||
constinit static thread_local const int &r2;
|
||||
};
|
||||
constinit thread_local const int &T::r1 = gl;
|
||||
constinit thread_local const int &T::r2 = 42; // { dg-error "variable .T::r2. does not have a constant initializer|not a constant expression" }
|
5
gcc/testsuite/g++.dg/cpp2a/constinit6.C
Normal file
5
gcc/testsuite/g++.dg/cpp2a/constinit6.C
Normal file
@ -0,0 +1,5 @@
|
||||
// PR c++/91360 - Implement C++20 P1143R2: constinit
|
||||
// { dg-do compile { target c++17_down } }
|
||||
// { dg-options "-Wc++20-compat" }
|
||||
|
||||
int constinit; // { dg-warning "identifier .constinit. is a keyword" }
|
11
gcc/testsuite/g++.dg/cpp2a/constinit7.C
Normal file
11
gcc/testsuite/g++.dg/cpp2a/constinit7.C
Normal file
@ -0,0 +1,11 @@
|
||||
// PR c++/91360 - Implement C++20 P1143R2: constinit
|
||||
// { dg-do compile { target c++11 } }
|
||||
|
||||
struct T {
|
||||
constexpr T(int) {}
|
||||
~T();
|
||||
};
|
||||
__constinit T x = { 42 };
|
||||
// ??? This should be rejected in C++14: copy initialization is not a constant
|
||||
// expression on a non-literal type in C++14. But 'constinit' is C++20 only.
|
||||
__constinit T y = 42;
|
18
gcc/testsuite/g++.dg/cpp2a/constinit8.C
Normal file
18
gcc/testsuite/g++.dg/cpp2a/constinit8.C
Normal file
@ -0,0 +1,18 @@
|
||||
// PR c++/91360 - Implement C++20 P1143R2: constinit
|
||||
// { dg-do compile { target c++2a } }
|
||||
// Variable templates.
|
||||
|
||||
int nonconst;
|
||||
|
||||
template<typename T>
|
||||
constinit T v1 = 42;
|
||||
|
||||
template<typename T>
|
||||
constinit T v2 = nonconst; // { dg-error "does not have a constant initializer|not usable" }
|
||||
|
||||
void
|
||||
fn ()
|
||||
{
|
||||
v1<int>;
|
||||
v2<int>;
|
||||
}
|
24
gcc/testsuite/g++.dg/cpp2a/constinit9.C
Normal file
24
gcc/testsuite/g++.dg/cpp2a/constinit9.C
Normal file
@ -0,0 +1,24 @@
|
||||
// PR c++/91360 - Implement C++20 P1143R2: constinit
|
||||
// { dg-do run { target c++2a } }
|
||||
// A run-time test.
|
||||
|
||||
constexpr int foo (int x) { return x; }
|
||||
constinit int b = foo(42);
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
if (b != 42)
|
||||
__builtin_abort ();
|
||||
// We can still modify 'b'.
|
||||
b = 10;
|
||||
if (b != 10)
|
||||
__builtin_abort ();
|
||||
|
||||
constinit static int s = foo(14);
|
||||
if (s != 14)
|
||||
__builtin_abort ();
|
||||
s++;
|
||||
if (s != 15)
|
||||
__builtin_abort ();
|
||||
}
|
Loading…
Reference in New Issue
Block a user