From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-ej1-x630.google.com (mail-ej1-x630.google.com [IPv6:2a00:1450:4864:20::630]) by sourceware.org (Postfix) with ESMTPS id 8B5223858C74 for ; Sat, 12 Nov 2022 16:13:03 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 8B5223858C74 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gmail.com Received: by mail-ej1-x630.google.com with SMTP id bj12so18803231ejb.13 for ; Sat, 12 Nov 2022 08:13:03 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=to:in-reply-to:cc:references:message-id:date:subject:mime-version :from:content-transfer-encoding:from:to:cc:subject:date:message-id :reply-to; bh=EVADSca8YkSSu0YtOnGud3BjsF7L22gl4O5qUCCgUzE=; b=AtWT3fZjMtEgBC7PoS69GqMhNCMsU89RVeDDON0VOSxiU2gBhFn05g06cyGuqMkUlL MhTFd0xhl+Xwq+BRF/lVdgv6GGy2SfHlQTlUMLo1bMvIrHGQ8UPqSV5fXjQRanga+5mM L4FSgxyKWaFA9fSIbqmM3V2ydWwmaSLfNECkw59EfrmnO3uEirrgiw4mX2jKgTwEiNag ziRvlLXxmA8xdCTNr79OhPLSCWYlUl4hFmqFgoDsMIUxsUb5EwZacEn2OCbTvIfplFy6 gcRlLQDWonKhZ7qWmEOUDDAtpLcMxxTC0HLcyXkSY34P2FjEBO/iQSJfQYORejzj3feV Hm0w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=to:in-reply-to:cc:references:message-id:date:subject:mime-version :from:content-transfer-encoding:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=EVADSca8YkSSu0YtOnGud3BjsF7L22gl4O5qUCCgUzE=; b=rPcLMZNE8HqOHbqT8FI8HBMUMP6jGyZLHo5/hgh+202ARztMPJQ2TNAsmyltxA62tS 2Xko1GQfHF51SeOXuPk+GyHRiqUB2//TrfginBwrTVjJCI7QnuqeFea1IC0gcsc8CNRp oI0mxiGMKBSuc5pqVNgVnIBSg2k/+9lacgG5A8BqP1EDV3+9nQFC8BD1r6vQfKxPuC3U Z0IZ+cVduAMJPHl6JHPOG59dA9nDaqOUMGcO2yF9P2+aD1T7YZDEip6rJWZJio9ZS6ze s+NFkw3MmsXj6XLhb0Epf0Z1ylw5cELfRDpu6RAOGd6eQjJxKEG1cCCVRfBLQCZMK7o+ 16kA== X-Gm-Message-State: ANoB5pk7bygU72ODZCZYB9gZxLig8BxP4PromOB2sQlIz2Nb9FXTHAyn NUhD6KQmeYzqWWxfkoPLZnnL3uDpQa8= X-Google-Smtp-Source: AA0mqf62gBKxfn9iIbADsoZ5aB6LvSNQylQZcAOqhCyud3YCsLWHo3oXDY0X0US+zk5WkH1Rv78TRA== X-Received: by 2002:a17:906:339b:b0:78d:3862:4488 with SMTP id v27-20020a170906339b00b0078d38624488mr5215746eja.683.1668269580522; Sat, 12 Nov 2022 08:13:00 -0800 (PST) Received: from smtpclient.apple (dynamic-077-002-014-019.77.2.pool.telefonica.de. [77.2.14.19]) by smtp.gmail.com with ESMTPSA id ay26-20020a056402203a00b00461816beef9sm2469767edb.14.2022.11.12.08.12.56 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Sat, 12 Nov 2022 08:12:59 -0800 (PST) Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable From: Richard Biener Mime-Version: 1.0 (1.0) Subject: Re: c: C2x constexpr Date: Sat, 12 Nov 2022 17:12:42 +0100 Message-Id: References: <2dd14b67-f6f-6b30-46a0-8166a1e515c9@codesourcery.com> Cc: gcc-patches@gcc.gnu.org In-Reply-To: <2dd14b67-f6f-6b30-46a0-8166a1e515c9@codesourcery.com> To: Joseph Myers X-Mailer: iPhone Mail (20B101) X-Spam-Status: No, score=-9.5 required=5.0 tests=BAYES_00,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,FREEMAIL_FROM,GIT_PATCH_0,KAM_SHORT,KAM_STOCKGEN,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_PASS,TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: > Am 12.11.2022 um 05:56 schrieb Joseph Myers : >=20 > =EF=BB=BF[Global / middle-end reviewers, note there is a dfp.cc change her= e > that needs review.] >=20 > Implement C2x constexpr (a feature based on the C++ one but much more > minimal, with only constexpr variables, not functions). >=20 > I believe this implementation is fully functional for use of this > feature. However, there are several things that seem unclear about > the specification that I'll need to raise in NB comments. There are > also areas where there may be followup bug fixes because the > implementation doesn't reject some more obscure cases that ought to be > rejected: cases where a constexpr initializer for floating type meets > the constraints for a constant expression in initializers but not > those for an arithmetic constant expression (previously we haven't had > to track whether something is an arithmetic constant expression in > detail, unlike with integer constant expressions), and some cases > where a tag or struct or union member gets declared indirectly in the > declaration specifiers or declarator of a constexpr declaration, which > is not permitted (modulo lack of clarity in the specification) for > underspecified declarations in general (the cases of a declaration in > the initializer, or a tagged type being directly declared as a type > specifier, are already detected). >=20 > Cases of ambiguity in the specification include: >=20 > * Many questions (previously raised in WG14 discussions) over the rule > about what conversions do or do not involve a change of value that's > not allowed in a constexpr initializer, that aren't properly > addressed by the normative text (and where the footnote on the > subject isn't very clear either, and the examples don't necessarily > follow from the normative text). I've made a series of choices > there, that include disallowing all conversions between real and > complex types or between binary and decimal floating types in > constexpr initializers, that might not necessarily agree with how > things end up getting clarified. >=20 > The dfp.cc change also arises here, to allow quiet NaN initializers > of one DFP type to be used in a constexpr initializer for another > DFP type (as is possible for signaling NaNs) by ensuring the result > of such a conversion is properly marked as canonical (note that most > of the DFP code doesn't actually do anything with NaN payloads at > all). >=20 > * Various issues with what exactly counts as part of a declaration for > the purposes of the rule on underspecified declarations not > declaring any identifiers other than ordinary identifiers (and not > declaring more than one ordinary identifier, though the latter is > undefined behavior). These include cases where the declaration of a > struct / union / enum type appears inside typeof or alignas in the > declaration specifiers (the latter also applies with auto), or in > the declarator (e.g. an array size or in a parameter declaration). > The issues are similar to those involved in C90 DR#115 and C99 DRs > #277 and #341; the intent may not be the same in all the different > cases involved, but it's not clear that the normative wording in the > various places is sufficient to deduce the differences in intent. >=20 > * The wording about producing a compound literal constant using member > access is present in one place but another place only applies that > to named constants. >=20 > * It's not clear when a structure or union constant (a constexpr > variable or compound literal with structure or union type, or a > member with such type extracted by a series of member access > operations) can itself be used in an initializer (constexpr or > otherwise). Based on general wording for initializers not having > been changed, the working draft might only strictly allow it at > automatic storage duration (but elsewhere it would be undefined > behavior, not a constraint violation, so no diagnostic required) - > since that's the only case mentioned where a single expression of > structure or union type can be used to initialize an object of such > a type. But it definitely seems to be allowed in even constexpr > initializers at automatic storage duration - and since generally > constexpr initializers (any storage duration) are *more* constrained > than ordinary static storage duration initializers, it would seem > odd for it not to be allowed at static storage duration. >=20 > * When you do allow such initializers, it's then not entirely clear > how the constraint that constexpr pointer initializers must be null > pointer constants should be applied (given that a constexpr object > of pointer type is a null pointer but *not* a null pointer > constant). My guess would be that a constexpr struct or union > containing such a field should still be allowed as an initializer, > but the wording could be read otherwise. >=20 > * It also becomes important with constexpr exactly what kind of > constant expression an implicit zero initializer is; the wording for > default initialization only really deals with the value of the > initializer and not what kind of constant it is. In particular, > this affects whether {} is a valid constexpr initializer for a > pointer not of type void *, since the wording only talks about a > null pointer, not whether it's a null pointer *constant*. I assumed > that it should be a null pointer constant in that case. >=20 > * It's also not entirely clear whether constexpr can be used in the > declaration part of a for loop (which "shall only declare > identifiers for objects having storage class auto or register"). I > interpreted it as allowed (treating such objects as implicitly auto > just like those with no storage class specifiers), but it could also > be argued that constexpr is another storage class specifier and so > not allowed there. >=20 > Bootstrapped with no regressions for x86_64-pc-linux-gnu. OK to > commit (the dfp.cc changes)? OK, Richard=20 > gcc/ > * dfp.cc (decimal_from_binary): Convert a canonical NaN to a > canonical NaN. >=20 > gcc/c-family/ > * c-common.cc (c_common_reswords): Use D_C2X instead of D_CXXONLY. >=20 > gcc/c/ > * c-decl.cc (start_underspecified_init) > (finish_underspecified_init): Handle name =3D=3D NULL_TREE for > compound literals. > (merge_decls): Merge C_DECL_DECLARED_CONSTEXPR. > (shadow_tag_warned): Check for constexpr. > (start_decl): Add parameter do_push. > (build_compound_literal): Set C_DECL_DECLARED_CONSTEXPR. > (grokdeclarator): Handle constexpr. > (finish_struct): Set C_TYPE_FIELDS_NON_CONSTEXPR. > (declspecs_add_scspec): Handle constexpr. > * c-parser.cc (c_token_starts_compound_literal) > (c_token_starts_declspecs, c_parser_declaration_or_fndef) > (c_parser_declspecs, c_parser_gnu_attribute_any_word) > (c_parser_compound_literal_scspecs) > (c_parser_postfix_expression_after_paren_type): Handle constexpr. > Update calls to start_init. > (c_parser_declaration_or_fndef, c_parser_initializer) > (c_parser_initval): Pass true for new argument of > convert_lvalue_to_rvalue. Call convert_lvalue_to_rvalue for > constexpr compound literals. > (c_parser_static_assert_declaration_no_semi) > (c_parser_enum_specifier, c_parser_struct_declaration) > (c_parser_alignas_specifier, c_parser_initelt, c_parser_label): > Call convert_lvalue_to_rvalue on expressions required to be > integer constant expressions. > (c_parser_omp_declare_reduction): Update call to start_init. > * c-tree.h (C_TYPE_FIELDS_NON_CONSTEXPR) > (C_DECL_DECLARED_CONSTEXPR): New macros. > (struct c_declspecs): Add constexpr_p. > (start_decl, convert_lvalue_to_rvalue, start_init): Update > prototypes. > * c-typeck.cc (require_constant_value, require_constant_elements): > Change to bool. > (require_constexpr_value, maybe_get_constexpr_init) > (constexpr_init_fits_real_type, check_constexpr_init): New. > (convert_lvalue_to_rvalue): Add new parameter for_init. Call > maybe_get_constexpr_init. > (store_init_value): Update call to digest_init. > (digest_init): Add parameters int_const_expr, arith_const_expr and > require_constexpr. Check constexpr initializers. > (constructor_top_level): Remove. > (struct initializer_stack): Remove top_level. Add > require_constexpr_value. > (start_init): Remove parameter top_level. Add parameters > init_require_constant and init_require_constexpr. Save > require_constexpr_value on stack. > (pop_init_level): Use a null pointer constant for zero initializer > of pointer initialized with {}. > (output_init_element): Update call to digest_init. Avoid passing > null pointer constants of pointer type through digest_init a > second time when initializing a constexpr object. >=20 > gcc/testsuite/ > * gcc.dg/c11-keywords-1.c: Also test constexpr. > * gcc.dg/c2x-constexpr-1.c, gcc.dg/c2x-constexpr-2a.c, > gcc.dg/c2x-constexpr-2b.c, gcc.dg/c2x-constexpr-3.c, > gcc.dg/c2x-constexpr-4.c, gcc.dg/c2x-constexpr-5.c, > gcc.dg/c2x-constexpr-6.c, gcc.dg/c2x-constexpr-7.c, > gcc.dg/c2x-constexpr-8.c, gcc.dg/c2x-constexpr-9.c, > gcc.dg/dfp/c2x-constexpr-dfp-1.c, > gcc.dg/dfp/c2x-constexpr-dfp-2.c, gcc.dg/gnu2x-constexpr-1.c, > gcc.target/i386/excess-precision-11.c, > gcc.target/i386/excess-precision-12.c: New tests. >=20 > diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc > index 5890c18bdc3..71507d4cb0a 100644 > --- a/gcc/c-family/c-common.cc > +++ b/gcc/c-family/c-common.cc > @@ -440,7 +440,7 @@ const struct c_common_resword c_common_reswords[] =3D > { "class", RID_CLASS, D_CXX_OBJC | D_CXXWARN }, > { "const", RID_CONST, 0 }, > { "consteval", RID_CONSTEVAL, D_CXXONLY | D_CXX20 | D_CXXWARN }, > - { "constexpr", RID_CONSTEXPR, D_CXXONLY | D_CXX11 | D_CXXWARN }, > + { "constexpr", RID_CONSTEXPR, D_C2X | 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 }, > diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc > index a99b7456055..36de77814ba 100644 > --- a/gcc/c/c-decl.cc > +++ b/gcc/c/c-decl.cc > @@ -1480,26 +1480,34 @@ static bool in_underspecified_init; > means that NAME is shadowed inside its initializer, so neither the > definition being initialized, nor any definition from an outer > scope, may be referenced during that initializer. Return state to > - be passed to finish_underspecified_init. */ > + be passed to finish_underspecified_init. If NAME is NULL_TREE, the > + underspecified object is a (constexpr) compound literal; there is > + no shadowing in that case, but all the other restrictions on > + underspecified object definitions still apply. */ > unsigned int > start_underspecified_init (location_t loc, tree name) > { > bool prev =3D in_underspecified_init; > bool ok; > - tree decl =3D build_decl (loc, VAR_DECL, name, error_mark_node); > - C_DECL_UNDERSPECIFIED (decl) =3D 1; > - struct c_scope *scope =3D current_scope; > - struct c_binding *b =3D I_SYMBOL_BINDING (name); > - if (b && B_IN_SCOPE (b, scope)) > - { > - error_at (loc, "underspecified declaration of %qE, which is already= " > - "declared in this scope", name); > - ok =3D false; > - } > + if (name =3D=3D NULL_TREE) > + ok =3D true; > else > { > - bind (name, decl, scope, false, false, loc); > - ok =3D true; > + tree decl =3D build_decl (loc, VAR_DECL, name, error_mark_node); > + C_DECL_UNDERSPECIFIED (decl) =3D 1; > + struct c_scope *scope =3D current_scope; > + struct c_binding *b =3D I_SYMBOL_BINDING (name); > + if (b && B_IN_SCOPE (b, scope)) > + { > + error_at (loc, "underspecified declaration of %qE, which is already= " > + "declared in this scope", name); > + ok =3D false; > + } > + else > + { > + bind (name, decl, scope, false, false, loc); > + ok =3D true; > + } > } > in_underspecified_init =3D true; > return ok | (prev << 1); > @@ -1508,11 +1516,12 @@ start_underspecified_init (location_t loc, tree na= me) > /* Finish an underspecified object definition for NAME, before that > name is bound to the real declaration instead of a placeholder. > PREV_STATE is the value returned by the call to > - start_underspecified_init. */ > + start_underspecified_init. If NAME is NULL_TREE, this means a > + compound literal, as for start_underspecified_init. */ > void > finish_underspecified_init (tree name, unsigned int prev_state) > { > - if (prev_state & 1) > + if (name !=3D NULL_TREE && (prev_state & 1)) > { > /* A VAR_DECL was bound to the name to shadow any previous > declarations for the name; remove that binding now. */ > @@ -2745,6 +2754,15 @@ merge_decls (tree newdecl, tree olddecl, tree newty= pe, tree oldtype) > if (DECL_INITIAL (newdecl) =3D=3D NULL_TREE) > DECL_INITIAL (newdecl) =3D DECL_INITIAL (olddecl); >=20 > + /* Merge 'constexpr' information. */ > + if (VAR_P (olddecl) && VAR_P (newdecl)) > + { > + if (C_DECL_DECLARED_CONSTEXPR (olddecl)) > + C_DECL_DECLARED_CONSTEXPR (newdecl) =3D 1; > + else if (C_DECL_DECLARED_CONSTEXPR (newdecl)) > + C_DECL_DECLARED_CONSTEXPR (olddecl) =3D 1; > + } > + > /* Merge the threadprivate attribute. */ > if (VAR_P (olddecl) && C_DECL_THREADPRIVATE_P (olddecl)) > C_DECL_THREADPRIVATE_P (newdecl) =3D 1; > @@ -4944,6 +4962,12 @@ shadow_tag_warned (const struct c_declspecs *declsp= ecs, int warned) > warned =3D 1; > } >=20 > + if (declspecs->constexpr_p) > + { > + error ("% in empty declaration"); > + warned =3D 1; > + } > + > if (current_scope =3D=3D file_scope && declspecs->storage_class =3D=3D c= sc_auto) > { > error ("% in file-scope empty declaration"); > @@ -5301,7 +5325,7 @@ c_decl_attributes (tree *node, tree attributes, int f= lags) > This is called as soon as the type information and variable name > have been parsed, before parsing the initializer if any. > Here we create the ..._DECL node, fill in its type, > - and put it on the list of decls for the current context. > + and (if DO_PUSH) put it on the list of decls for the current context. > When nonnull, set *LASTLOC to the location of the prior declaration > of the same entity if one exists. > The ..._DECL node is returned as the value. > @@ -5316,7 +5340,8 @@ c_decl_attributes (tree *node, tree attributes, int f= lags) >=20 > tree > start_decl (struct c_declarator *declarator, struct c_declspecs *declspecs= , > - bool initialized, tree attributes, location_t *lastloc /* =3D NUL= L */) > + bool initialized, tree attributes, bool do_push /* =3D true */, > + location_t *lastloc /* =3D NULL */) > { > tree decl; > tree tem; > @@ -5489,15 +5514,20 @@ start_decl (struct c_declarator *declarator, struc= t c_declspecs *declspecs, >=20 > /* Add this decl to the current scope. > TEM may equal DECL or it may be a previous decl of the same name. */= > - tem =3D pushdecl (decl); > - > - if (initialized && DECL_EXTERNAL (tem)) > + if (do_push) > { > - DECL_EXTERNAL (tem) =3D 0; > - TREE_STATIC (tem) =3D 1; > - } > + tem =3D pushdecl (decl); > + > + if (initialized && DECL_EXTERNAL (tem)) > + { > + DECL_EXTERNAL (tem) =3D 0; > + TREE_STATIC (tem) =3D 1; > + } >=20 > - return tem; > + return tem; > + } > + else > + return decl; > } >=20 > /* Subroutine of finish_decl. TYPE is the type of an uninitialized object > @@ -6214,6 +6244,7 @@ build_compound_literal (location_t loc, tree type, t= ree init, bool non_const, > DECL_ARTIFICIAL (decl) =3D 1; > DECL_IGNORED_P (decl) =3D 1; > C_DECL_COMPOUND_LITERAL_P (decl) =3D 1; > + C_DECL_DECLARED_CONSTEXPR (decl) =3D scspecs && scspecs->constexpr_p; > TREE_TYPE (decl) =3D type; > if (threadp) > set_decl_tls_model (decl, decl_default_tls_model (decl)); > @@ -6501,6 +6532,7 @@ grokdeclarator (const struct c_declarator *declarato= r, > { > tree type =3D declspecs->type; > bool threadp =3D declspecs->thread_p; > + bool constexprp =3D declspecs->constexpr_p; > enum c_storage_class storage_class =3D declspecs->storage_class; > int constp; > int restrictp; > @@ -6743,6 +6775,7 @@ grokdeclarator (const struct c_declarator *declarato= r, >=20 > if (funcdef_flag > && (threadp > + || constexprp > || storage_class =3D=3D csc_auto > || storage_class =3D=3D csc_register > || storage_class =3D=3D csc_typedef)) > @@ -6759,6 +6792,9 @@ grokdeclarator (const struct c_declarator *declarato= r, > error_at (loc, "function definition declared %qs", > declspecs->thread_gnu_p ? "__thread" : "_Thread_local"); > threadp =3D false; > + /* The parser ensures a constexpr function definition never > + reaches here. */ > + gcc_assert (!constexprp); > if (storage_class =3D=3D csc_auto > || storage_class =3D=3D csc_register > || storage_class =3D=3D csc_typedef) > @@ -6766,10 +6802,12 @@ grokdeclarator (const struct c_declarator *declara= tor, > } > else if (decl_context !=3D NORMAL && (storage_class !=3D csc_none > || threadp > + || constexprp > || declspecs->c2x_auto_p)) > { > if (decl_context =3D=3D PARM > && storage_class =3D=3D csc_register > + && !constexprp > && !declspecs->c2x_auto_p) > ; > else > @@ -6796,6 +6834,7 @@ grokdeclarator (const struct c_declarator *declarato= r, > } > storage_class =3D csc_none; > threadp =3D false; > + constexprp =3D false; > } > } > else if (storage_class =3D=3D csc_extern > @@ -7843,7 +7882,7 @@ grokdeclarator (const struct c_declarator *declarato= r, > } > else if (TREE_CODE (type) =3D=3D FUNCTION_TYPE) > { > - if (storage_class =3D=3D csc_register || threadp) > + if (storage_class =3D=3D csc_register || threadp || constexprp) > { > error_at (loc, "invalid storage class for function %qE", name); > } > @@ -7943,6 +7982,32 @@ grokdeclarator (const struct c_declarator *declarat= or, > /* An uninitialized decl with `extern' is a reference. */ > int extern_ref =3D !initialized && storage_class =3D=3D csc_extern; >=20 > + if (constexprp) > + { > + /* The type of a constexpr variable must not be variably > + modified, volatile, atomic or restrict qualified or > + have a member with such a qualifier. const > + qualification is implicitly added, and, at file scope, > + has internal linkage. */ > + if (variably_modified_type_p (type, NULL_TREE)) > + error_at (loc, "% object has variably modified " > + "type"); > + if (type_quals > + & (TYPE_QUAL_VOLATILE | TYPE_QUAL_RESTRICT | TYPE_QUAL_ATOMIC)) > + error_at (loc, "invalid qualifiers for % object"); > + else > + { > + tree type_no_array =3D strip_array_types (type); > + if (RECORD_OR_UNION_TYPE_P (type_no_array) > + && C_TYPE_FIELDS_NON_CONSTEXPR (type_no_array)) > + error_at (loc, "invalid qualifiers for field of " > + "% object"); > + } > + type_quals |=3D TYPE_QUAL_CONST; > + if (current_scope =3D=3D file_scope) > + storage_class =3D csc_static; > + } > + > type =3D c_build_qualified_type (type, type_quals, orig_qual_type, > orig_qual_indirect); >=20 > @@ -7969,6 +8034,8 @@ grokdeclarator (const struct c_declarator *declarato= r, > VAR_DECL, declarator->u.id.id, type); > if (size_varies) > C_DECL_VARIABLE_SIZE (decl) =3D 1; > + if (constexprp) > + C_DECL_DECLARED_CONSTEXPR (decl) =3D 1; >=20 > if (declspecs->inline_p) > pedwarn (loc, 0, "variable %q+D declared %", decl); > @@ -9119,13 +9186,13 @@ finish_struct (location_t loc, tree t, tree fieldl= ist, tree attributes, >=20 > DECL_CONTEXT (x) =3D t; >=20 > + tree t1 =3D strip_array_types (TREE_TYPE (x)); > /* If any field is const, the structure type is pseudo-const. */ > if (TREE_READONLY (x)) > C_TYPE_FIELDS_READONLY (t) =3D 1; > else > { > /* A field that is pseudo-const makes the structure likewise. */ > - tree t1 =3D strip_array_types (TREE_TYPE (x)); > if (RECORD_OR_UNION_TYPE_P (t1) && C_TYPE_FIELDS_READONLY (t1)) > C_TYPE_FIELDS_READONLY (t) =3D 1; > } > @@ -9133,7 +9200,18 @@ finish_struct (location_t loc, tree t, tree fieldli= st, tree attributes, > /* Any field that is volatile means variables of this type must be > treated in some ways as volatile. */ > if (TREE_THIS_VOLATILE (x)) > - C_TYPE_FIELDS_VOLATILE (t) =3D 1; > + { > + C_TYPE_FIELDS_VOLATILE (t) =3D 1; > + C_TYPE_FIELDS_NON_CONSTEXPR (t) =3D 1; > + } > + > + /* Any field that is volatile, restrict-qualified or atomic > + means the type cannot be used for a constexpr object. */ > + if (TYPE_QUALS (t1) > + & (TYPE_QUAL_VOLATILE | TYPE_QUAL_RESTRICT | TYPE_QUAL_ATOMIC)) > + C_TYPE_FIELDS_NON_CONSTEXPR (t) =3D 1; > + else if (RECORD_OR_UNION_TYPE_P (t1) && C_TYPE_FIELDS_NON_CONSTEXPR= (t1)) > + C_TYPE_FIELDS_NON_CONSTEXPR (t) =3D 1; >=20 > /* Any field of nominal variable size implies structure is too. */ > if (C_DECL_VARIABLE_SIZE (x)) > @@ -9335,6 +9413,7 @@ finish_struct (location_t loc, tree t, tree fieldlis= t, tree attributes, > TYPE_TRANSPARENT_AGGR (x) =3D TYPE_TRANSPARENT_AGGR (t); > C_TYPE_FIELDS_READONLY (x) =3D C_TYPE_FIELDS_READONLY (t); > C_TYPE_FIELDS_VOLATILE (x) =3D C_TYPE_FIELDS_VOLATILE (t); > + C_TYPE_FIELDS_NON_CONSTEXPR (x) =3D C_TYPE_FIELDS_NON_CONSTEXPR (t)= ; > C_TYPE_VARIABLE_SIZE (x) =3D C_TYPE_VARIABLE_SIZE (t); > C_TYPE_INCOMPLETE_VARS (x) =3D NULL_TREE; > } > @@ -12266,6 +12345,8 @@ declspecs_add_scspec (location_t loc, > error ("%qE used with %", scspec); > else if (specs->storage_class =3D=3D csc_typedef) > error ("%qE used with %", scspec); > + else if (specs->constexpr_p) > + error ("%qE used with %", scspec); > else > { > specs->thread_p =3D true; > @@ -12323,6 +12404,18 @@ declspecs_add_scspec (location_t loc, > specs->c2x_auto_p =3D false; > } > break; > + case RID_CONSTEXPR: > + dupe =3D specs->constexpr_p; > + if (specs->storage_class =3D=3D csc_extern) > + error ("%qE used with %", scspec); > + else if (specs->storage_class =3D=3D csc_typedef) > + error ("%qE used with %", scspec); > + else if (specs->thread_p) > + error ("%qE used with %qs", scspec, > + specs->thread_gnu_p ? "__thread" : "_Thread_local"); > + else > + specs->constexpr_p =3D true; > + break; > default: > gcc_unreachable (); > } > @@ -12352,6 +12445,12 @@ declspecs_add_scspec (location_t loc, > scspec); > specs->thread_p =3D false; > } > + if (n !=3D csc_auto && n !=3D csc_register && n !=3D csc_static > + && specs->constexpr_p) > + { > + error ("% used with %qE", scspec); > + specs->constexpr_p =3D false; > + } > } > } > return specs; > diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc > index d70697b1d63..1d144bba24d 100644 > --- a/gcc/c/c-parser.cc > +++ b/gcc/c/c-parser.cc > @@ -677,6 +677,7 @@ c_token_starts_compound_literal (c_token *token) > case CPP_KEYWORD: > switch (token->keyword) > { > + case RID_CONSTEXPR: > case RID_REGISTER: > case RID_STATIC: > case RID_THREAD: > @@ -795,6 +796,7 @@ c_token_starts_declspecs (c_token *token) > case RID_ALIGNAS: > case RID_ATOMIC: > case RID_AUTO_TYPE: > + case RID_CONSTEXPR: > return true; > default: > if (token->keyword >=3D RID_FIRST_INT_N > @@ -2108,6 +2110,32 @@ c_parser_declaration_or_fndef (c_parser *parser, bo= ol fndef_ok, > bool any_auto_type_p =3D gnu_auto_type_p || std_auto_type_p; > gcc_assert (!(gnu_auto_type_p && std_auto_type_p)); > const char *auto_type_keyword =3D gnu_auto_type_p ? "__auto_type" : "aut= o"; > + if (specs->constexpr_p) > + { > + /* An underspecified declaration may not declare tags or members > + or structures or unions; it is undefined behavior to declare > + the members of an enumeration. Where the structure, union or > + enumeration type is declared within an initializer, this is > + diagnosed elsewhere. Diagnose here the case of declaring > + such a type in the type specifiers of a constexpr > + declaration. */ > + switch (specs->typespec_kind) > + { > + case ctsk_tagfirstref: > + case ctsk_tagfirstref_attrs: > + error_at (here, "%qT declared in underspecified object declaration"= , > + specs->type); > + break; > + > + case ctsk_tagdef: > + error_at (here, "%qT defined in underspecified object declaration",= > + specs->type); > + break; > + > + default: > + break; > + } > + } > if (c_parser_next_token_is (parser, CPP_SEMICOLON)) > { > bool handled_assume =3D false; > @@ -2257,7 +2285,7 @@ c_parser_declaration_or_fndef (c_parser *parser, boo= l fndef_ok, > bool dummy =3D false; > timevar_id_t tv; > tree fnbody =3D NULL_TREE; > - tree std_auto_name =3D NULL_TREE; > + tree underspec_name =3D NULL_TREE; > /* Declaring either one or more declarators (in which case we > should diagnose if there were no declaration specifiers) or a > function definition (in which case the diagnostic for > @@ -2296,7 +2324,14 @@ c_parser_declaration_or_fndef (c_parser *parser, bo= ol fndef_ok, > c_parser_skip_to_end_of_block_or_statement (parser); > return; > } > - std_auto_name =3D d->u.id.id; > + underspec_name =3D d->u.id.id; > + } > + else if (specs->constexpr_p) > + { > + struct c_declarator *d =3D declarator; > + while (d->kind !=3D cdk_id) > + d =3D d->declarator; > + underspec_name =3D d->u.id.id; > } > if (c_parser_next_token_is (parser, CPP_EQ) > || c_parser_next_token_is (parser, CPP_COMMA) > @@ -2343,9 +2378,13 @@ c_parser_declaration_or_fndef (c_parser *parser, bo= ol fndef_ok, > rich_location richloc (line_table, init_loc); > unsigned int underspec_state =3D 0; > if (std_auto_type_p) > - underspec_state =3D start_underspecified_init (init_loc, > - std_auto_name); > - start_init (NULL_TREE, asm_name, global_bindings_p (), &richloc= ); > + underspec_state =3D > + start_underspecified_init (init_loc, underspec_name); > + start_init (NULL_TREE, asm_name, > + (global_bindings_p () > + || specs->storage_class =3D=3D csc_static > + || specs->constexpr_p), > + specs->constexpr_p, &richloc); > /* A parameter is initialized, which is invalid. Don't > attempt to instrument the initializer. */ > int flag_sanitize_save =3D flag_sanitize; > @@ -2364,7 +2403,8 @@ c_parser_declaration_or_fndef (c_parser *parser, boo= l fndef_ok, > else > init =3D c_parser_expr_no_commas (parser, NULL); > if (std_auto_type_p) > - finish_underspecified_init (std_auto_name, underspec_state); > + finish_underspecified_init (underspec_name, > + underspec_state); > flag_sanitize =3D flag_sanitize_save; > if (gnu_auto_type_p > && TREE_CODE (init.value) =3D=3D COMPONENT_REF > @@ -2372,7 +2412,8 @@ c_parser_declaration_or_fndef (c_parser *parser, boo= l fndef_ok, > error_at (here, > "%<__auto_type%> used with a bit-field" > " initializer"); > - init =3D convert_lvalue_to_rvalue (init_loc, init, true, true);= > + init =3D convert_lvalue_to_rvalue (init_loc, init, true, true, > + true); > tree init_type =3D TREE_TYPE (init.value); > bool vm_type =3D variably_modified_type_p (init_type, > NULL_TREE); > @@ -2417,17 +2458,26 @@ c_parser_declaration_or_fndef (c_parser *parser, b= ool fndef_ok, > else > { > /* The declaration of the variable is in effect while > - its initializer is parsed. */ > + its initializer is parsed, except for a constexpr > + variable. */ > + init_loc =3D c_parser_peek_token (parser)->location; > + rich_location richloc (line_table, init_loc); > + unsigned int underspec_state =3D 0; > + if (specs->constexpr_p) > + underspec_state =3D > + start_underspecified_init (init_loc, underspec_name); > d =3D start_decl (declarator, specs, true, > - chainon (postfix_attrs, all_prefix_attrs)); > + chainon (postfix_attrs, > + all_prefix_attrs), > + !specs->constexpr_p); > if (!d) > d =3D error_mark_node; > - if (omp_declare_simd_clauses) > + if (!specs->constexpr_p && omp_declare_simd_clauses) > c_finish_omp_declare_simd (parser, d, NULL_TREE, > omp_declare_simd_clauses); > - init_loc =3D c_parser_peek_token (parser)->location; > - rich_location richloc (line_table, init_loc); > - start_init (d, asm_name, global_bindings_p (), &richloc); > + start_init (d, asm_name, > + TREE_STATIC (d) || specs->constexpr_p, > + specs->constexpr_p, &richloc); > /* A parameter is initialized, which is invalid. Don't > attempt to instrument the initializer. */ > int flag_sanitize_save =3D flag_sanitize; > @@ -2435,6 +2485,15 @@ c_parser_declaration_or_fndef (c_parser *parser, bo= ol fndef_ok, > flag_sanitize =3D 0; > init =3D c_parser_initializer (parser, d); > flag_sanitize =3D flag_sanitize_save; > + if (specs->constexpr_p) > + { > + finish_underspecified_init (underspec_name, > + underspec_state); > + d =3D pushdecl (d); > + if (omp_declare_simd_clauses) > + c_finish_omp_declare_simd (parser, d, NULL_TREE, > + omp_declare_simd_clauses); > + } > finish_init (); > } > if (oacc_routine_data) > @@ -2448,18 +2507,19 @@ c_parser_declaration_or_fndef (c_parser *parser, b= ool fndef_ok, > } > else > { > - if (any_auto_type_p) > + if (any_auto_type_p || specs->constexpr_p) > { > error_at (here, > "%qs requires an initialized data declaration", > - auto_type_keyword); > + any_auto_type_p ? auto_type_keyword : "constexpr"); > c_parser_skip_to_end_of_block_or_statement (parser); > return; > } >=20 > location_t lastloc =3D UNKNOWN_LOCATION; > tree attrs =3D chainon (postfix_attrs, all_prefix_attrs); > - tree d =3D start_decl (declarator, specs, false, attrs, &lastlo= c); > + tree d =3D start_decl (declarator, specs, false, attrs, true, > + &lastloc); > if (d && TREE_CODE (d) =3D=3D FUNCTION_DECL) > { > /* Find the innermost declarator that is neither cdk_id > @@ -2540,11 +2600,11 @@ c_parser_declaration_or_fndef (c_parser *parser, b= ool fndef_ok, > } > if (c_parser_next_token_is (parser, CPP_COMMA)) > { > - if (any_auto_type_p) > + if (any_auto_type_p || specs->constexpr_p) > { > error_at (here, > "%qs may only be used with a single declarator", > - auto_type_keyword); > + any_auto_type_p ? auto_type_keyword : "constexpr"); > c_parser_skip_to_end_of_block_or_statement (parser); > return; > } > @@ -2577,11 +2637,11 @@ c_parser_declaration_or_fndef (c_parser *parser, b= ool fndef_ok, > return; > } > } > - else if (any_auto_type_p) > + else if (any_auto_type_p || specs->constexpr_p) > { > error_at (here, > "%qs requires an initialized data declaration", > - auto_type_keyword); > + any_auto_type_p ? auto_type_keyword : "constexpr"); > c_parser_skip_to_end_of_block_or_statement (parser); > return; > } > @@ -2789,7 +2849,9 @@ c_parser_static_assert_declaration_no_semi (c_parser= *parser) > if (!parens.require_open (parser)) > return; > location_t value_tok_loc =3D c_parser_peek_token (parser)->location; > - value =3D c_parser_expr_no_commas (parser, NULL).value; > + value =3D convert_lvalue_to_rvalue (value_tok_loc, > + c_parser_expr_no_commas (parser, NULL), > + true, true).value; > value_loc =3D EXPR_LOC_OR_LOC (value, value_tok_loc); > if (c_parser_next_token_is (parser, CPP_COMMA)) > { > @@ -3092,6 +3154,7 @@ c_parser_declspecs (c_parser *parser, struct c_decls= pecs *specs, > case RID_NORETURN: > case RID_AUTO: > case RID_THREAD: > + case RID_CONSTEXPR: > if (!scspec_ok) > goto out; > attrs_ok =3D true; > @@ -3462,7 +3525,10 @@ c_parser_enum_specifier (c_parser *parser) > { > c_parser_consume_token (parser); > value_loc =3D c_parser_peek_token (parser)->location; > - enum_value =3D c_parser_expr_no_commas (parser, NULL).value; > + enum_value =3D convert_lvalue_to_rvalue (value_loc, > + (c_parser_expr_no_commas > + (parser, NULL)), > + true, true).value; > } > else > enum_value =3D NULL_TREE; > @@ -3900,7 +3966,11 @@ c_parser_struct_declaration (c_parser *parser) > if (c_parser_next_token_is (parser, CPP_COLON)) > { > c_parser_consume_token (parser); > - width =3D c_parser_expr_no_commas (parser, NULL).value; > + location_t loc =3D c_parser_peek_token (parser)->location; > + width =3D convert_lvalue_to_rvalue (loc, > + (c_parser_expr_no_commas > + (parser, NULL)), > + true, true).value; > } > if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) > postfix_attrs =3D c_parser_gnu_attributes (parser); > @@ -4069,7 +4139,9 @@ c_parser_alignas_specifier (c_parser * parser) > false, true, 1); > } > else > - ret =3D c_parser_expr_no_commas (parser, NULL).value; > + ret =3D convert_lvalue_to_rvalue (loc, > + c_parser_expr_no_commas (parser, NULL), > + true, true).value; > parens.skip_until_found_close (parser); > return ret; > } > @@ -4817,6 +4889,7 @@ c_parser_gnu_attribute_any_word (c_parser *parser) > case RID_TRANSACTION_CANCEL: > case RID_ATOMIC: > case RID_AUTO_TYPE: > + case RID_CONSTEXPR: > case RID_INT_N_0: > case RID_INT_N_1: > case RID_INT_N_2: > @@ -5538,8 +5611,10 @@ c_parser_initializer (c_parser *parser, tree decl) > && !warn_init_self) > suppress_warning (decl, OPT_Winit_self); > if (TREE_CODE (ret.value) !=3D STRING_CST > - && TREE_CODE (ret.value) !=3D COMPOUND_LITERAL_EXPR) > - ret =3D convert_lvalue_to_rvalue (loc, ret, true, true); > + && (TREE_CODE (ret.value) !=3D COMPOUND_LITERAL_EXPR > + || C_DECL_DECLARED_CONSTEXPR (COMPOUND_LITERAL_EXPR_DECL > + (ret.value)))) > + ret =3D convert_lvalue_to_rvalue (loc, ret, true, true, true); > return ret; > } > } > @@ -5685,6 +5760,7 @@ c_parser_initelt (c_parser *parser, struct obstack *= braced_init_obstack) > } > else > { > + struct c_expr first_expr; > tree first, second; > location_t ellipsis_loc =3D UNKNOWN_LOCATION; /* Quiet warning. = */ > location_t array_index_loc =3D UNKNOWN_LOCATION; > @@ -5728,11 +5804,13 @@ c_parser_initelt (c_parser *parser, struct obstack= * braced_init_obstack) > rec =3D objc_get_class_reference (id); > goto parse_message_args; > } > - first =3D c_parser_expr_no_commas (parser, NULL).value; > - mark_exp_read (first); > + array_index_loc =3D c_parser_peek_token (parser)->location; > + first_expr =3D c_parser_expr_no_commas (parser, NULL); > + mark_exp_read (first_expr.value); > if (c_parser_next_token_is (parser, CPP_ELLIPSIS) > || c_parser_next_token_is (parser, CPP_CLOSE_SQUARE)) > goto array_desig_after_first; > + first =3D first_expr.value; > /* Expression receiver. So far only one part > without commas has been parsed; there might be > more of the expression. */ > @@ -5767,14 +5845,21 @@ c_parser_initelt (c_parser *parser, struct obstack= * braced_init_obstack) > } > c_parser_consume_token (parser); > array_index_loc =3D c_parser_peek_token (parser)->location; > - first =3D c_parser_expr_no_commas (parser, NULL).value; > - mark_exp_read (first); > + first_expr =3D c_parser_expr_no_commas (parser, NULL); > + mark_exp_read (first_expr.value); > array_desig_after_first: > + first_expr =3D convert_lvalue_to_rvalue (array_index_loc, > + first_expr, > + true, true); > + first =3D first_expr.value; > if (c_parser_next_token_is (parser, CPP_ELLIPSIS)) > { > ellipsis_loc =3D c_parser_peek_token (parser)->location; > c_parser_consume_token (parser); > - second =3D c_parser_expr_no_commas (parser, NULL).value; > + second =3D convert_lvalue_to_rvalue (ellipsis_loc, > + (c_parser_expr_no_commas > + (parser, NULL)), > + true, true).value; > mark_exp_read (second); > } > else > @@ -5847,8 +5932,10 @@ c_parser_initval (c_parser *parser, struct c_expr *= after, > init =3D c_parser_expr_no_commas (parser, after); > if (init.value !=3D NULL_TREE > && TREE_CODE (init.value) !=3D STRING_CST > - && TREE_CODE (init.value) !=3D COMPOUND_LITERAL_EXPR) > - init =3D convert_lvalue_to_rvalue (loc, init, true, true); > + && (TREE_CODE (init.value) !=3D COMPOUND_LITERAL_EXPR > + || C_DECL_DECLARED_CONSTEXPR (COMPOUND_LITERAL_EXPR_DECL > + (init.value)))) > + init =3D convert_lvalue_to_rvalue (loc, init, true, true, true); > } > process_init_element (loc, init, false, braced_init_obstack); > } > @@ -6205,7 +6292,9 @@ c_parser_label (c_parser *parser, tree std_attrs) > { > tree exp1, exp2; > c_parser_consume_token (parser); > - exp1 =3D c_parser_expr_no_commas (parser, NULL).value; > + exp1 =3D convert_lvalue_to_rvalue (loc1, > + c_parser_expr_no_commas (parser, NULL), > + true, true).value; > if (c_parser_next_token_is (parser, CPP_COLON)) > { > c_parser_consume_token (parser); > @@ -6214,7 +6303,10 @@ c_parser_label (c_parser *parser, tree std_attrs) > else if (c_parser_next_token_is (parser, CPP_ELLIPSIS)) > { > c_parser_consume_token (parser); > - exp2 =3D c_parser_expr_no_commas (parser, NULL).value; > + exp2 =3D convert_lvalue_to_rvalue (loc1, > + c_parser_expr_no_commas (parser, > + NULL), > + true, true).value; > if (c_parser_require (parser, CPP_COLON, "expected %<:%>")) > label =3D do_case (loc1, exp1, exp2, std_attrs); > } > @@ -8411,6 +8503,7 @@ c_parser_compound_literal_scspecs (c_parser *parser)= > { > switch (c_parser_peek_token (parser)->keyword) > { > + case RID_CONSTEXPR: > case RID_REGISTER: > case RID_STATIC: > case RID_THREAD: > @@ -10697,17 +10790,71 @@ c_parser_postfix_expression_after_paren_type (c_= parser *parser, > location_t start_loc; > tree type_expr =3D NULL_TREE; > bool type_expr_const =3D true; > + bool constexpr_p =3D scspecs ? scspecs->constexpr_p : false; > + unsigned int underspec_state =3D 0; > check_compound_literal_type (type_loc, type_name); > rich_location richloc (line_table, type_loc); > - start_init (NULL_TREE, NULL, 0, &richloc); > - type =3D groktypename (type_name, &type_expr, &type_expr_const); > start_loc =3D c_parser_peek_token (parser)->location; > + if (constexpr_p) > + { > + underspec_state =3D start_underspecified_init (start_loc, NULL_TREE= ); > + /* A constexpr compound literal is subject to the constraints on > + underspecified declarations, which may not declare tags or > + members or structures or unions; it is undefined behavior to > + declare the members of an enumeration. Where the structure, > + union or enumeration type is declared within the compound > + literal initializer, this is diagnosed elsewhere as a result > + of the above call to start_underspecified_init. Diagnose > + here the case of declaring such a type in the type specifiers > + of the compound literal. */ > + switch (type_name->specs->typespec_kind) > + { > + case ctsk_tagfirstref: > + case ctsk_tagfirstref_attrs: > + error_at (type_loc, "%qT declared in % compound literal= ", > + type_name->specs->type); > + break; > + > + case ctsk_tagdef: > + error_at (type_loc, "%qT defined in % compound literal"= , > + type_name->specs->type); > + break; > + > + default: > + break; > + } > + } > + start_init (NULL_TREE, NULL, > + (global_bindings_p () > + || (scspecs && scspecs->storage_class =3D=3D csc_static) > + || constexpr_p), constexpr_p, &richloc); > + type =3D groktypename (type_name, &type_expr, &type_expr_const); > if (type !=3D error_mark_node && C_TYPE_VARIABLE_SIZE (type)) > { > error_at (type_loc, "compound literal has variable size"); > type =3D error_mark_node; > } > + if (constexpr_p && type !=3D error_mark_node) > + { > + tree type_no_array =3D strip_array_types (type); > + /* The type of a constexpr object must not be variably modified > + (which applies to all compound literals), volatile, atomic or > + restrict qualified or have a member with such a qualifier. > + const qualification is implicitly added. */ > + if (TYPE_QUALS (type_no_array) > + & (TYPE_QUAL_VOLATILE | TYPE_QUAL_RESTRICT | TYPE_QUAL_ATOMIC)) > + error_at (type_loc, "invalid qualifiers for % object"); > + else if (RECORD_OR_UNION_TYPE_P (type_no_array) > + && C_TYPE_FIELDS_NON_CONSTEXPR (type_no_array)) > + error_at (type_loc, "invalid qualifiers for field of " > + "% object"); > + type =3D c_build_qualified_type (type, > + (TYPE_QUALS (type_no_array) > + | TYPE_QUAL_CONST)); > + } > init =3D c_parser_braced_init (parser, type, false, NULL, NULL_TREE); > + if (constexpr_p) > + finish_underspecified_init (NULL_TREE, underspec_state); > finish_init (); > maybe_warn_string_init (type_loc, type, init); >=20 > @@ -23194,7 +23341,7 @@ c_parser_omp_declare_reduction (c_parser *parser, e= num pragma_context context) > tree st =3D push_stmt_list (); > location_t loc =3D c_parser_peek_token (parser)->location; > rich_location richloc (line_table, loc); > - start_init (omp_priv, NULL_TREE, 0, &richloc); > + start_init (omp_priv, NULL_TREE, false, false, &richloc); > struct c_expr init =3D c_parser_initializer (parser, omp_priv); > finish_init (); > finish_decl (omp_priv, loc, init.value, > diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h > index 8116e5cc984..c287124c990 100644 > --- a/gcc/c/c-tree.h > +++ b/gcc/c/c-tree.h > @@ -34,6 +34,11 @@ along with GCC; see the file COPYING3. If not see > /* In a RECORD_TYPE or UNION_TYPE, nonzero if any component is volatile. *= / > #define C_TYPE_FIELDS_VOLATILE(TYPE) TREE_LANG_FLAG_2 (TYPE) >=20 > +/* In a RECORD_TYPE or UNION_TYPE, nonzero if any component is > + volatile, restrict-qualified or atomic; that is, has a type not > + permitted for a constexpr object. */ > +#define C_TYPE_FIELDS_NON_CONSTEXPR(TYPE) TREE_LANG_FLAG_4 (TYPE) > + > /* In a RECORD_TYPE or UNION_TYPE or ENUMERAL_TYPE > nonzero if the definition of the type has already started. */ > #define C_TYPE_BEING_DEFINED(TYPE) TYPE_LANG_FLAG_0 (TYPE) > @@ -104,6 +109,10 @@ along with GCC; see the file COPYING3. If not see > definition. */ > #define C_DECL_UNDERSPECIFIED(DECL) DECL_LANG_FLAG_7 (DECL) >=20 > +/* Set on VAR_DECLs declared as 'constexpr'. */ > +#define C_DECL_DECLARED_CONSTEXPR(DECL) \ > + DECL_LANG_FLAG_8 (VAR_DECL_CHECK (DECL)) > + > /* Nonzero for a decl which either doesn't exist or isn't a prototype. > N.B. Could be simplified if all built-in decls had complete prototypes > (but this is presently difficult because some of them need FILE*). */ > @@ -439,6 +448,8 @@ struct c_declspecs { > no type specifier appears later in these declaration > specifiers. */ > BOOL_BITFIELD c2x_auto_p : 1; > + /* Whether "constexpr" was specified. */ > + BOOL_BITFIELD constexpr_p : 1; > /* The address space that the declaration belongs to. */ > addr_space_t address_space; > }; > @@ -662,7 +673,7 @@ extern void shadow_tag_warned (const struct c_declspec= s *, int); > extern tree start_enum (location_t, struct c_enum_contents *, tree, tree);= > extern bool start_function (struct c_declspecs *, struct c_declarator *, t= ree); > extern tree start_decl (struct c_declarator *, struct c_declspecs *, bool,= > - tree, location_t * =3D NULL); > + tree, bool =3D true, location_t * =3D NULL); > extern tree start_struct (location_t, enum tree_code, tree, > class c_struct_parse_info **); > extern void store_parm_decls (void); > @@ -733,7 +744,7 @@ extern struct c_expr default_function_array_conversion= (location_t, > extern struct c_expr default_function_array_read_conversion (location_t, > struct c_expr); > extern struct c_expr convert_lvalue_to_rvalue (location_t, struct c_expr, > - bool, bool); > + bool, bool, bool =3D false); > extern tree decl_constant_value_1 (tree, bool); > extern void mark_exp_read (tree); > extern tree composite_type (tree, tree); > @@ -756,7 +767,7 @@ extern tree c_cast_expr (location_t, struct c_type_nam= e *, tree); > extern tree build_c_cast (location_t, tree, tree); > extern void store_init_value (location_t, tree, tree, tree); > extern void maybe_warn_string_init (location_t, tree, struct c_expr); > -extern void start_init (tree, tree, int, rich_location *); > +extern void start_init (tree, tree, bool, bool, rich_location *); > extern void finish_init (void); > extern void really_start_incremental_init (tree); > extern void finish_implicit_inits (location_t, struct obstack *); > diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc > index 636098444b4..e06f052eb46 100644 > --- a/gcc/c/c-typeck.cc > +++ b/gcc/c/c-typeck.cc > @@ -84,8 +84,9 @@ location_t c_last_sizeof_loc; > initializer" message within this initializer. */ > static int found_missing_braces; >=20 > -static int require_constant_value; > -static int require_constant_elements; > +static bool require_constant_value; > +static bool require_constant_elements; > +static bool require_constexpr_value; >=20 > static bool null_pointer_constant_p (const_tree); > static tree qualify_type (tree, tree); > @@ -109,7 +110,8 @@ static void push_member_name (tree); > static int spelling_length (void); > static char *print_spelling (char *); > static void warning_init (location_t, int, const char *); > -static tree digest_init (location_t, tree, tree, tree, bool, bool, int); > +static tree digest_init (location_t, tree, tree, tree, bool, bool, bool, b= ool, > + bool, bool); > static void output_init_element (location_t, tree, tree, bool, tree, tree,= bool, > bool, struct obstack *); > static void output_pending_init_elements (int, struct obstack *); > @@ -2133,20 +2135,91 @@ really_atomic_lvalue (tree expr) > return true; > } >=20 > +/* If EXPR is a named constant (C2x) derived from a constexpr variable > + - that is, a reference to such a variable, or a member extracted by > + a sequence of structure and union (but not array) member accesses > + (where union member accesses must access the same member as > + initialized) - then return the corresponding initializer; > + otherwise, return NULL_TREE. */ > + > +static tree > +maybe_get_constexpr_init (tree expr) > +{ > + tree decl =3D NULL_TREE; > + if (TREE_CODE (expr) =3D=3D VAR_DECL) > + decl =3D expr; > + else if (TREE_CODE (expr) =3D=3D COMPOUND_LITERAL_EXPR) > + decl =3D COMPOUND_LITERAL_EXPR_DECL (expr); > + if (decl > + && C_DECL_DECLARED_CONSTEXPR (decl) > + && DECL_INITIAL (decl) !=3D NULL_TREE > + && !error_operand_p (DECL_INITIAL (decl))) > + return DECL_INITIAL (decl); > + if (TREE_CODE (expr) !=3D COMPONENT_REF) > + return NULL_TREE; > + tree inner =3D maybe_get_constexpr_init (TREE_OPERAND (expr, 0)); > + if (inner =3D=3D NULL_TREE) > + return NULL_TREE; > + while ((CONVERT_EXPR_P (inner) || TREE_CODE (inner) =3D=3D NON_LVALUE_E= XPR) > + && !error_operand_p (inner) > + && (TYPE_MAIN_VARIANT (TREE_TYPE (inner)) > + =3D=3D TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (inner, 0)))))= > + inner =3D TREE_OPERAND (inner, 0); > + if (TREE_CODE (inner) !=3D CONSTRUCTOR) > + return NULL_TREE; > + tree field =3D TREE_OPERAND (expr, 1); > + unsigned HOST_WIDE_INT cidx; > + tree cfield, cvalue; > + bool have_other_init =3D false; > + FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (inner), cidx, cfield, cvalu= e) > + { > + if (cfield =3D=3D field) > + return cvalue; > + have_other_init =3D true; > + } > + if (TREE_CODE (TREE_TYPE (inner)) =3D=3D UNION_TYPE > + && (have_other_init || field !=3D TYPE_FIELDS (TREE_TYPE (inner))))= > + return NULL_TREE; > + /* Return a default initializer. */ > + if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (expr))) > + return build_constructor (TREE_TYPE (expr), NULL); > + return build_zero_cst (TREE_TYPE (expr)); > +} > + > /* Convert expression EXP (location LOC) from lvalue to rvalue, > including converting functions and arrays to pointers if CONVERT_P. > - If READ_P, also mark the expression as having been read. */ > + If READ_P, also mark the expression as having been read. If > + FOR_INIT, constexpr expressions of structure and union type should > + be replaced by the corresponding CONSTRUCTOR; otherwise, only > + constexpr scalars (including elements of structures and unions) are > + replaced by their initializers. */ >=20 > struct c_expr > convert_lvalue_to_rvalue (location_t loc, struct c_expr exp, > - bool convert_p, bool read_p) > + bool convert_p, bool read_p, bool for_init) > { > + bool force_non_npc =3D false; > if (read_p) > mark_exp_read (exp.value); > if (convert_p) > exp =3D default_function_array_conversion (loc, exp); > if (!VOID_TYPE_P (TREE_TYPE (exp.value))) > exp.value =3D require_complete_type (loc, exp.value); > + if (for_init || !RECORD_OR_UNION_TYPE_P (TREE_TYPE (exp.value))) > + { > + tree init =3D maybe_get_constexpr_init (exp.value); > + if (init !=3D NULL_TREE) > + { > + /* A named constant of pointer type or type nullptr_t is not > + a null pointer constant even if the initializer is > + one. */ > + if (TREE_CODE (init) =3D=3D INTEGER_CST > + && !INTEGRAL_TYPE_P (TREE_TYPE (init)) > + && integer_zerop (init)) > + force_non_npc =3D true; > + exp.value =3D init; > + } > + } > if (really_atomic_lvalue (exp.value)) > { > vec *params; > @@ -2187,6 +2260,8 @@ convert_lvalue_to_rvalue (location_t loc, struct c_e= xpr exp, > if (convert_p && !error_operand_p (exp.value) > && (TREE_CODE (TREE_TYPE (exp.value)) !=3D ARRAY_TYPE)) > exp.value =3D convert (build_qualified_type (TREE_TYPE (exp.value), TY= PE_UNQUALIFIED), exp.value); > + if (force_non_npc) > + exp.value =3D build1 (NOP_EXPR, TREE_TYPE (exp.value), exp.value); > return exp; > } >=20 > @@ -6050,7 +6125,7 @@ build_c_cast (location_t loc, tree type, tree expr) > if (!maybe_const) > t =3D c_wrap_maybe_const (t, true); > t =3D digest_init (loc, type, t, > - NULL_TREE, false, true, 0); > + NULL_TREE, false, false, false, true, false, false); > TREE_CONSTANT (t) =3D TREE_CONSTANT (value); > return t; > } > @@ -7851,6 +7926,8 @@ store_init_value (location_t init_loc, tree decl, tr= ee init, tree origtype) > { > tree value, type; > bool npc =3D false; > + bool int_const_expr =3D false; > + bool arith_const_expr =3D false; >=20 > /* If variable's type was invalidly declared, just ignore it. */ >=20 > @@ -7861,9 +7938,19 @@ store_init_value (location_t init_loc, tree decl, t= ree init, tree origtype) > /* Digest the specified initializer into an expression. */ >=20 > if (init) > - npc =3D null_pointer_constant_p (init); > - value =3D digest_init (init_loc, type, init, origtype, npc, > - true, TREE_STATIC (decl)); > + { > + npc =3D null_pointer_constant_p (init); > + int_const_expr =3D (TREE_CODE (init) =3D=3D INTEGER_CST > + && !TREE_OVERFLOW (init) > + && INTEGRAL_TYPE_P (TREE_TYPE (init))); > + /* Not fully determined before folding. */ > + arith_const_expr =3D true; > + } > + bool constexpr_p =3D (TREE_CODE (decl) =3D=3D VAR_DECL > + && C_DECL_DECLARED_CONSTEXPR (decl)); > + value =3D digest_init (init_loc, type, init, origtype, npc, int_const_e= xpr, > + arith_const_expr, true, > + TREE_STATIC (decl) || constexpr_p, constexpr_p); >=20 > /* Store the expression if valid; else report error. */ >=20 > @@ -8033,12 +8120,151 @@ print_spelling (char *buffer) > return buffer; > } >=20 > +/* Check whether INIT, a floating or integer constant, is > + representable in TYPE, a real floating type with the same radix. > + Return true if OK, false if not. */ > +static bool > +constexpr_init_fits_real_type (tree type, tree init) > +{ > + gcc_assert (TREE_CODE (type) =3D=3D REAL_TYPE); > + gcc_assert (TREE_CODE (init) =3D=3D INTEGER_CST || TREE_CODE (init) =3D= =3D REAL_CST); > + if (TREE_CODE (init) =3D=3D REAL_CST > + && TYPE_MODE (TREE_TYPE (init)) =3D=3D TYPE_MODE (type)) > + /* Same mode, no conversion required. */ > + return true; > + if (TREE_CODE (init) =3D=3D INTEGER_CST) > + { > + tree converted =3D build_real_from_int_cst (type, init); > + bool fail =3D false; > + wide_int w =3D real_to_integer (&TREE_REAL_CST (converted), &fail, > + TYPE_PRECISION (TREE_TYPE (init))); > + return !fail && wi::eq_p (w, wi::to_wide (init)); > + } > + /* exact_real_truncate is not quite right here, since it doesn't > + allow even an exact conversion to subnormal values. */ > + REAL_VALUE_TYPE t; > + real_convert (&t, TYPE_MODE (type), &TREE_REAL_CST (init)); > + return real_identical (&t, &TREE_REAL_CST (init)); > +} > + > +/* Check whether INIT (location LOC) is valid as a 'constexpr' > + initializer for type TYPE, and give an error if not. INIT has > + already been folded and verified to be constant. > + NULL_POINTER_CONSTANT, INT_CONST_EXPR and ARITH_CONST_EXPR say > + whether it is a null pointer constant, integer constant expression > + or arithmetic constant expression, respectively. If TYPE is not a > + scalar type, this function does nothing. */ > + > +static void > +check_constexpr_init (location_t loc, tree type, tree init, > + bool null_pointer_constant, bool int_const_expr, > + bool arith_const_expr) > +{ > + if (POINTER_TYPE_P (type)) > + { > + /* The initializer must be a null pointer constant. */ > + if (!null_pointer_constant) > + error_at (loc, "% pointer initializer is not a " > + "null pointer constant"); > + return; > + } > + if (INTEGRAL_TYPE_P (type)) > + { > + /* The initializer must be an integer constant expression, > + representable in the target type. */ > + if (!int_const_expr) > + error_at (loc, "% integer initializer is not an " > + "integer constant expression"); > + if (!int_fits_type_p (init, type)) > + error_at (loc, "% initializer not representable in " > + "type of object"); > + return; > + } > + /* We don't apply any extra checks to extension types such as vector > + or fixed-point types. */ > + if (TREE_CODE (type) !=3D REAL_TYPE && TREE_CODE (type) !=3D COMPLEX_TY= PE) > + return; > + if (!arith_const_expr) > + { > + error_at (loc, "% initializer is not an arithmetic " > + "constant expression"); > + return; > + } > + /* We don't apply any extra checks to complex integers. */ > + if (TREE_CODE (type) =3D=3D COMPLEX_TYPE > + && TREE_CODE (TREE_TYPE (type)) !=3D REAL_TYPE) > + return; > + /* Both the normative text and the relevant footnote are unclear, as > + of the C2x CD, about what exactly counts as a change of value in > + floating-point cases. Here, we consider all conversions between > + binary and decimal types (even of infinities and NaNs, where > + quantum exponents are not involved) as involving a change of > + value, and likewise for conversions between real and complex > + types (even when the complex constant has imaginary part positive > + zero), and conversions of signaling NaN to a different machine > + mode. But we allow exact conversions of integers to binary or > + decimal floating types, and exact conversions between different > + binary types or different decimal types, where "exact" in the > + decimal case requires the quantum exponent to be preserved. */ > + if (TREE_CODE (TREE_TYPE (init)) =3D=3D COMPLEX_TYPE > + && TREE_CODE (type) =3D=3D REAL_TYPE) > + { > + error_at (loc, "% initializer for a real type is of " > + "complex type"); > + return; > + } > + if (TREE_CODE (type) =3D=3D COMPLEX_TYPE > + && TREE_CODE (TREE_TYPE (init)) !=3D COMPLEX_TYPE) > + { > + error_at (loc, "% initializer for a complex type is of "= > + "real type"); > + return; > + } > + if (TREE_CODE (type) =3D=3D REAL_TYPE > + && TREE_CODE (TREE_TYPE (init)) =3D=3D REAL_TYPE) > + { > + if (DECIMAL_FLOAT_TYPE_P (type) > + && !DECIMAL_FLOAT_TYPE_P (TREE_TYPE (init))) > + { > + error_at (loc, "% initializer for a decimal " > + "floating-point type is of binary type"); > + return; > + } > + else if (DECIMAL_FLOAT_TYPE_P (TREE_TYPE (init)) > + && !DECIMAL_FLOAT_TYPE_P (type)) > + { > + error_at (loc, "% initializer for a binary " > + "floating-point type is of decimal type"); > + return; > + } > + } > + bool fits; > + if (TREE_CODE (type) =3D=3D COMPLEX_TYPE) > + { > + gcc_assert (TREE_CODE (init) =3D=3D COMPLEX_CST); > + fits =3D (constexpr_init_fits_real_type (TREE_TYPE (type), > + TREE_REALPART (init)) > + && constexpr_init_fits_real_type (TREE_TYPE (type), > + TREE_IMAGPART (init))); > + } > + else > + fits =3D constexpr_init_fits_real_type (type, init); > + if (!fits) > + error_at (loc, "% initializer not representable in " > + "type of object"); > +} > + > /* Digest the parser output INIT as an initializer for type TYPE. > Return a C expression of type TYPE to represent the initial value. >=20 > If ORIGTYPE is not NULL_TREE, it is the original type of INIT. >=20 > - NULL_POINTER_CONSTANT is true if INIT is a null pointer constant. > + NULL_POINTER_CONSTANT is true if INIT is a null pointer constant, > + INT_CONST_EXPR is true if INIT is an integer constant expression, > + and ARITH_CONST_EXPR is true if INIT is, or might be, an arithmetic > + constant expression, false if it has already been determined in the > + caller that it is not (but folding may have made the value passed here= > + indistinguishable from an arithmetic constant expression). >=20 > If INIT is a string constant, STRICT_STRING is true if it is > unparenthesized or we should not warn here for it being parenthesized. > @@ -8047,12 +8273,14 @@ print_spelling (char *buffer) > INIT_LOC is the location of the INIT. >=20 > REQUIRE_CONSTANT requests an error if non-constant initializers or > - elements are seen. */ > + elements are seen. REQUIRE_CONSTEXPR means the stricter requirements > + on initializers for 'constexpr' objects apply. */ >=20 > static tree > digest_init (location_t init_loc, tree type, tree init, tree origtype, > - bool null_pointer_constant, bool strict_string, > - int require_constant) > + bool null_pointer_constant, bool int_const_expr, > + bool arith_const_expr, bool strict_string, > + bool require_constant, bool require_constexpr) > { > enum tree_code code =3D TREE_CODE (type); > tree inside_init =3D init; > @@ -8075,6 +8303,20 @@ digest_init (location_t init_loc, tree type, tree i= nit, tree origtype, > } > inside_init =3D c_fully_fold (inside_init, require_constant, &maybe_= const); > } > + /* TODO: this may not detect all cases of expressions folding to > + constants that are not arithmetic constant expressions. */ > + if (!maybe_const) > + arith_const_expr =3D false; > + else if (!INTEGRAL_TYPE_P (TREE_TYPE (inside_init)) > + && TREE_CODE (TREE_TYPE (inside_init)) !=3D REAL_TYPE > + && TREE_CODE (TREE_TYPE (inside_init)) !=3D COMPLEX_TYPE) > + arith_const_expr =3D false; > + else if (TREE_CODE (inside_init) !=3D INTEGER_CST > + && TREE_CODE (inside_init) !=3D REAL_CST > + && TREE_CODE (inside_init) !=3D COMPLEX_CST) > + arith_const_expr =3D false; > + else if (TREE_OVERFLOW (inside_init)) > + arith_const_expr =3D false; >=20 > /* Initialization of an array of chars from a string constant > optionally enclosed in braces. */ > @@ -8132,6 +8374,25 @@ digest_init (location_t init_loc, tree type, tree i= nit, tree origtype, > return error_mark_node; > } >=20 > + if (require_constexpr > + && TYPE_UNSIGNED (typ1) !=3D TYPE_UNSIGNED (typ2)) > + { > + /* Check if all characters of the string can be > + represented in the type of the constexpr object being > + initialized. */ > + unsigned HOST_WIDE_INT len =3D TREE_STRING_LENGTH (inside_init)= ; > + const unsigned char *p =3D > + (const unsigned char *) TREE_STRING_POINTER (inside_init); > + gcc_assert (CHAR_TYPE_SIZE =3D=3D 8 && CHAR_BIT =3D=3D 8); > + for (unsigned i =3D 0; i < len; i++) > + if (p[i] > 127) > + { > + error_init (init_loc, "% initializer not " > + "representable in type of object"); > + break; > + } > + } > + > if (TYPE_DOMAIN (type) !=3D NULL_TREE > && TYPE_SIZE (type) !=3D NULL_TREE > && TREE_CODE (TYPE_SIZE (type)) =3D=3D INTEGER_CST) > @@ -8294,6 +8555,10 @@ digest_init (location_t init_loc, tree type, tree i= nit, tree origtype, > else if (require_constant && !maybe_const) > pedwarn_init (init_loc, OPT_Wpedantic, > "initializer element is not a constant expression"); > + else if (require_constexpr) > + check_constexpr_init (init_loc, type, inside_init, > + null_pointer_constant, int_const_expr, > + arith_const_expr); >=20 > /* Added to enable additional -Wsuggest-attribute=3Dformat warnings.= */ > if (TREE_CODE (TREE_TYPE (inside_init)) =3D=3D POINTER_TYPE) > @@ -8312,6 +8577,7 @@ digest_init (location_t init_loc, tree type, tree in= it, tree origtype, > || code =3D=3D POINTER_TYPE || code =3D=3D ENUMERAL_TYPE || code =3D= =3D BOOLEAN_TYPE > || code =3D=3D COMPLEX_TYPE || code =3D=3D VECTOR_TYPE) > { > + tree unconverted_init =3D inside_init; > if (TREE_CODE (TREE_TYPE (init)) =3D=3D ARRAY_TYPE > && (TREE_CODE (init) =3D=3D STRING_CST > || TREE_CODE (init) =3D=3D COMPOUND_LITERAL_EXPR)) > @@ -8345,6 +8611,10 @@ digest_init (location_t init_loc, tree type, tree i= nit, tree origtype, > else if (require_constant && !maybe_const) > pedwarn_init (init_loc, OPT_Wpedantic, > "initializer element is not a constant expression"); > + else if (require_constexpr) > + check_constexpr_init (init_loc, type, unconverted_init, > + null_pointer_constant, int_const_expr, > + arith_const_expr); >=20 > return inside_init; > } > @@ -8444,9 +8714,6 @@ static int constructor_depth; > such as (struct foo) {...}. */ > static tree constructor_decl; >=20 > -/* Nonzero if this is an initializer for a top-level decl. */ > -static int constructor_top_level; > - > /* Nonzero if there were any member designators in this initializer. */ > static int constructor_designated; >=20 > @@ -8523,9 +8790,9 @@ struct initializer_stack > struct spelling *spelling; > struct spelling *spelling_base; > int spelling_size; > - char top_level; > char require_constant_value; > char require_constant_elements; > + char require_constexpr_value; > char designated; > rich_location *missing_brace_richloc; > }; > @@ -8535,7 +8802,8 @@ static struct initializer_stack *initializer_stack; > /* Prepare to parse and output the initializer for variable DECL. */ >=20 > void > -start_init (tree decl, tree asmspec_tree ATTRIBUTE_UNUSED, int top_level,= > +start_init (tree decl, tree asmspec_tree ATTRIBUTE_UNUSED, > + bool init_require_constant, bool init_require_constexpr, > rich_location *richloc) > { > const char *locus; > @@ -8544,13 +8812,13 @@ start_init (tree decl, tree asmspec_tree ATTRIBUTE= _UNUSED, int top_level, > p->decl =3D constructor_decl; > p->require_constant_value =3D require_constant_value; > p->require_constant_elements =3D require_constant_elements; > + p->require_constexpr_value =3D require_constexpr_value; > p->constructor_stack =3D constructor_stack; > p->constructor_range_stack =3D constructor_range_stack; > p->elements =3D constructor_elements; > p->spelling =3D spelling; > p->spelling_base =3D spelling_base; > p->spelling_size =3D spelling_size; > - p->top_level =3D constructor_top_level; > p->next =3D initializer_stack; > p->missing_brace_richloc =3D richloc; > p->designated =3D constructor_designated; > @@ -8558,13 +8826,13 @@ start_init (tree decl, tree asmspec_tree ATTRIBUTE= _UNUSED, int top_level, >=20 > constructor_decl =3D decl; > constructor_designated =3D 0; > - constructor_top_level =3D top_level; >=20 > + require_constant_value =3D init_require_constant; > + require_constexpr_value =3D init_require_constexpr; > if (decl !=3D NULL_TREE && decl !=3D error_mark_node) > { > - require_constant_value =3D TREE_STATIC (decl); > require_constant_elements > - =3D ((TREE_STATIC (decl) || (pedantic && !flag_isoc99)) > + =3D ((init_require_constant || (pedantic && !flag_isoc99)) > /* For a scalar, you can always use any value to initialize, > even within braces. */ > && AGGREGATE_TYPE_P (TREE_TYPE (decl))); > @@ -8572,8 +8840,7 @@ start_init (tree decl, tree asmspec_tree ATTRIBUTE_U= NUSED, int top_level, > } > else > { > - require_constant_value =3D 0; > - require_constant_elements =3D 0; > + require_constant_elements =3D false; > locus =3D _("(anonymous)"); > } >=20 > @@ -8611,6 +8878,7 @@ finish_init (void) > constructor_decl =3D p->decl; > require_constant_value =3D p->require_constant_value; > require_constant_elements =3D p->require_constant_elements; > + require_constexpr_value =3D p->require_constexpr_value; > constructor_stack =3D p->constructor_stack; > constructor_designated =3D p->designated; > constructor_range_stack =3D p->constructor_range_stack; > @@ -8618,7 +8886,6 @@ finish_init (void) > spelling =3D p->spelling; > spelling_base =3D p->spelling_base; > spelling_size =3D p->spelling_size; > - constructor_top_level =3D p->top_level; > initializer_stack =3D p->next; > XDELETE (p); > } > @@ -9096,6 +9363,10 @@ pop_init_level (location_t loc, int implicit, > { > if (constructor_erroneous || constructor_type =3D=3D error_mark_node)= > ret.value =3D error_mark_node; > + else if (TREE_CODE (constructor_type) =3D=3D POINTER_TYPE) > + /* Ensure this is a null pointer constant in the case of a > + 'constexpr' object initialized with {}. */ > + ret.value =3D build_zero_cst (ptr_type_node); > else > ret.value =3D build_zero_cst (constructor_type); > } > @@ -9844,7 +10115,7 @@ output_init_element (location_t loc, tree value, tr= ee origtype, > { > tree semantic_type =3D NULL_TREE; > bool maybe_const =3D true; > - bool npc; > + bool npc, int_const_expr, arith_const_expr; >=20 > if (type =3D=3D error_mark_node || value =3D=3D error_mark_node) > { > @@ -9875,12 +10146,31 @@ output_init_element (location_t loc, tree value, t= ree origtype, > } >=20 > npc =3D null_pointer_constant_p (value); > + int_const_expr =3D (TREE_CODE (value) =3D=3D INTEGER_CST > + && !TREE_OVERFLOW (value) > + && INTEGRAL_TYPE_P (TREE_TYPE (value))); > + /* Not fully determined before folding. */ > + arith_const_expr =3D true; > if (TREE_CODE (value) =3D=3D EXCESS_PRECISION_EXPR) > { > semantic_type =3D TREE_TYPE (value); > value =3D TREE_OPERAND (value, 0); > } > value =3D c_fully_fold (value, require_constant_value, &maybe_const); > + /* TODO: this may not detect all cases of expressions folding to > + constants that are not arithmetic constant expressions. */ > + if (!maybe_const) > + arith_const_expr =3D false; > + else if (!INTEGRAL_TYPE_P (TREE_TYPE (value)) > + && TREE_CODE (TREE_TYPE (value)) !=3D REAL_TYPE > + && TREE_CODE (TREE_TYPE (value)) !=3D COMPLEX_TYPE) > + arith_const_expr =3D false; > + else if (TREE_CODE (value) !=3D INTEGER_CST > + && TREE_CODE (value) !=3D REAL_CST > + && TREE_CODE (value) !=3D COMPLEX_CST) > + arith_const_expr =3D false; > + else if (TREE_OVERFLOW (value)) > + arith_const_expr =3D false; >=20 > if (value =3D=3D error_mark_node) > constructor_erroneous =3D 1; > @@ -9903,8 +10193,18 @@ output_init_element (location_t loc, tree value, t= ree origtype, > tree new_value =3D value; > if (semantic_type) > new_value =3D build1 (EXCESS_PRECISION_EXPR, semantic_type, value); > - new_value =3D digest_init (loc, type, new_value, origtype, npc, strict_= string, > - require_constant_value); > + /* In the case of braces around a scalar initializer, the result of > + this initializer processing goes through digest_init again at the > + outer level. In the case of a constexpr initializer for a > + pointer, avoid converting a null pointer constant to something > + that is not a null pointer constant to avoid a spurious error > + from that second processing. */ > + if (!require_constexpr_value > + || !npc > + || TREE_CODE (constructor_type) !=3D POINTER_TYPE) > + new_value =3D digest_init (loc, type, new_value, origtype, npc, > + int_const_expr, arith_const_expr, strict_string, > + require_constant_value, require_constexpr_value); > if (new_value =3D=3D error_mark_node) > { > constructor_erroneous =3D 1; > @@ -9929,6 +10229,11 @@ output_init_element (location_t loc, tree value, t= ree origtype, > && (require_constant_value || require_constant_elements)) > pedwarn_init (loc, OPT_Wpedantic, > "initializer element is not a constant expression"); > + /* digest_init has already carried out the additional checks > + required for 'constexpr' initializers (using the information > + passed to it about whether the original initializer was certain > + kinds of constant expression), so that check does not need to be > + repeated here. */ >=20 > /* Issue -Wc++-compat warnings about initializing a bitfield with > enum type. */ > diff --git a/gcc/dfp.cc b/gcc/dfp.cc > index 7c1db7d4ebf..084ceb70a7d 100644 > --- a/gcc/dfp.cc > +++ b/gcc/dfp.cc > @@ -364,6 +364,12 @@ decimal_from_binary (REAL_VALUE_TYPE *to, const REAL_= VALUE_TYPE *from) > /* We convert to string, then to decNumber then to decimal128. */ > real_to_decimal (string, from, sizeof (string), 0, 1); > decimal_real_from_string (to, string); > + /* When a canonical NaN is originally created, it is not marked as > + decimal. Ensure the result of converting to another decimal type > + (which passes through this function) is also marked as > + canonical. */ > + if (from->cl =3D=3D rvc_nan && from->canonical) > + to->canonical =3D 1; > } >=20 > /* Helper function to real.cc:do_compare() to handle decimal internal > diff --git a/gcc/testsuite/gcc.dg/c11-keywords-1.c b/gcc/testsuite/gcc.dg/= c11-keywords-1.c > index 974ccfc75ca..997c1b0aff0 100644 > --- a/gcc/testsuite/gcc.dg/c11-keywords-1.c > +++ b/gcc/testsuite/gcc.dg/c11-keywords-1.c > @@ -5,6 +5,7 @@ > int alignas; > int alignof; > int bool; > +int constexpr; > int false; > int true; > int static_assert; > diff --git a/gcc/testsuite/gcc.dg/c2x-constexpr-1.c b/gcc/testsuite/gcc.dg= /c2x-constexpr-1.c > new file mode 100644 > index 00000000000..f7f64e2d300 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/c2x-constexpr-1.c > @@ -0,0 +1,312 @@ > +/* Test C2x constexpr. Valid code, compilation tests. */ > +/* { dg-do compile } */ > +/* { dg-options "-std=3Dc2x -pedantic-errors" } */ > + > +#include > + > +constexpr int v1 =3D 1; > +static_assert (v1 =3D=3D 1); > +extern typeof (v1) *pci; > +extern const int *pci; > +extern typeof (&(constexpr int) {}) pci; > +/* Redeclaring a constexpr object is OK (although it can't be declared be= fore > + the definition without undefined behavior). */ > +extern const int v1; > +static_assert (v1 =3D=3D 1); > +unsigned int constexpr v2 =3D 2; > +static_assert (v2 =3D=3D 2); > +extern typeof (v2) *pcui; > +extern const unsigned int *pcui; > +static constexpr char v3 =3D 3; > +static_assert (v3 =3D=3D 3); > +extern typeof (v3) *pcc; > +extern const char *pcc; > +constexpr void *v4 =3D 0; > +extern typeof (v4) *pcpv; > +extern void *const *pcpv; > +constexpr int *v5 =3D nullptr; > +extern typeof (v5) *pcpi; > +extern int *const *pcpi; > +constexpr double v6 =3D 3.5; > +extern typeof (v6) *pcd; > +extern const double *pcd; > +auto constexpr v7 =3D 1.0; > +extern typeof (v7) *pcd; > +constexpr auto v8 =3D 1.5f; > +extern typeof (v8) *pcf; > +extern const float *pcf; > +constexpr static long v9 =3D 2ULL; > +static_assert (v9 =3D=3D 2); > +extern typeof (v9) *pcl; > +extern const long *pcl; > +const short *v10 =3D &(constexpr short) { 10 }; > +/* Qualifiers that aren't permitted on a constexpr object itself are OK i= n a > + pointer target. */ > +constexpr volatile int *v11 =3D nullptr; > +extern typeof (v11) *pcpvi; > +extern volatile int *const *pcpvi; > +constexpr _Atomic int *v12 =3D nullptr; > +extern typeof (v12) *pcpai; > +extern _Atomic int *const *pcpai; > +constexpr int *restrict *v13 =3D nullptr; > +extern typeof (v13) cprpi; > +extern int *restrict *const cprpi; > +typedef int *P; > +constexpr restrict P *v14 =3D nullptr; > +extern typeof (v14) cprpi; > +struct s15 { volatile int a; _Atomic int b; int *restrict p; }; > +constexpr struct s15 *v16 =3D nullptr; > +constexpr char v17[3] =3D { 1, 2, 3 }; > +struct s18 { int a; int *b; double c; }; > +constexpr struct s18 v19 =3D { 12345ULL, 0, 19.0L }; > +static_assert (v19.a =3D=3D 12345); > +union u20 { int a; float b; }; > +constexpr union u20 v21 =3D { 1 }; > +static_assert (v21.a =3D=3D 1); > +constexpr union u20 v22 =3D { .b =3D 23.0 }; > +constexpr float v23 =3D (float) (1.0f / 3.0f); > +constexpr double v24 =3D (double) (1.0 / 3.0); > +constexpr struct s18 v25 =3D { 0, 0, (double) (1.0 / 3.0) }; > +static_assert (v25.a =3D=3D 0); > +constexpr char v26[] =3D "abc\xfe"; > +constexpr unsigned char v27[] =3D u8"xyz\xff"; > +constexpr unsigned char v28[] =3D "\x12\x7f"; > +constexpr signed char v29[] =3D "\x34\x66"; > +constexpr double v30 =3D (int) (double) 3.0 - (long) (double) 2.0; > +constexpr int v31 =3D 1 + 2 + (int) 3.0; > +static_assert (v31 =3D=3D 6); > +constexpr typeof (nullptr) v32 =3D nullptr; > +constexpr _Complex double v33 =3D __builtin_complex (1.0f, 3.0f / 2.0f); > +constexpr float v34 =3D 1234.0L; > +constexpr char v35 =3D 127ULL; > +#if FLT_MIN_EXP =3D=3D -125 && FLT_MANT_DIG =3D=3D 24 > +constexpr float v36 =3D 0x1p-149; > +constexpr float _Complex v37 =3D __builtin_complex (0x1p-149, 0x1p127); > +constexpr float v38 =3D 0xffffffUL; > +constexpr float v39 =3D -0xffffffL; > +constexpr float v40 =3D 0xffffff0L; > +constexpr float v41 =3D 1ULL << 63; > +#endif > +#if DBL_MIN_EXP =3D=3D -1021 && DBL_MANT_DIG =3D=3D 53 > +constexpr double v42 =3D 0x1p-1074L; > +constexpr _Complex double v43 =3D __builtin_complex (0x1p1023L, 0x1p-1074= L); > +constexpr double v44 =3D 0x1fffffffffffffULL; > +constexpr double v45 =3D -0x1fffffffffffffLL; > +constexpr double v46 =3D 0x3ffffffffffffeULL; > +constexpr double v47 =3D 1ULL << 63; > +#endif > +constexpr void *v48 =3D (void *) 0; > +constexpr int *v49 =3D (void *) 0L; > +constexpr long *v50 =3D 0LL; > +constexpr int v51 =3D {}; > +static_assert (v51 =3D=3D 0); > +constexpr float v52 =3D {}; > +constexpr long double v53 =3D {}; > +constexpr int *v54 =3D {}; > +constexpr void *v55 =3D {}; > +constexpr typeof (nullptr) v56 =3D {}; > +struct s57 { int *p; }; > +union u58 { int *p; }; > +constexpr int *v59 =3D 0; > +constexpr int *v60 =3D { 0 }; > +constexpr struct s57 v61 =3D { 0 }; > +constexpr struct s57 v62 =3D { { } }; /* { dg-warning "braces around scal= ar initializer" } */ > +constexpr struct s57 v63 =3D { { 0 } }; /* { dg-warning "braces around sc= alar initializer" } */ > +constexpr union u58 v64 =3D { 0 }; > +constexpr union u58 v65 =3D { { } }; /* { dg-warning "braces around scala= r initializer" } */ > +constexpr union u58 v66 =3D { { 0 } }; /* { dg-warning "braces around sca= lar initializer" } */ > +struct s67 { int a; float b; void *c; int *d; typeof (nullptr) e; int f; i= nt g[2]; }; > +struct s68 { struct s67 x; }; > +union u69 { int a; float b; void *c; int *d; struct s68 e; }; > +struct s70 { union u69 x; }; > +constexpr struct s67 v71 =3D { 1, 2.0, 0, 0, nullptr, 7, { 3, 4 } }; > +static_assert (v71.a =3D=3D 1); > +static_assert (v71.f =3D=3D 7); > +constexpr struct s67 v72 =3D v71; > +static_assert (v72.a =3D=3D 1); > +static_assert (v72.f =3D=3D 7); > +extern const struct s67 v71; > +constexpr auto v73 =3D v71; > +static_assert (v73.a =3D=3D 1); > +static_assert (v73.f =3D=3D 7); > +auto v74 =3D v71; > +constexpr struct s68 v75 =3D { v72 }; > +static_assert (v75.x.a =3D=3D 1); > +static_assert (v75.x.f =3D=3D 7); > +constexpr union u69 v76 =3D { }; > +static_assert (v76.a =3D=3D 0); > +constexpr union u69 v77 =3D { .e =3D v75 }; > +static_assert (v77.e.x.a =3D=3D 1); > +static_assert (v77.e.x.f =3D=3D 7); > +constexpr union u69 v78 =3D { .a =3D 1 }; > +static_assert (v78.a =3D=3D 1); > +constexpr union u69 v79 =3D { .e =3D { v72 } }; > +static_assert (v79.e.x.a =3D=3D 1); > +static_assert (v79.e.x.f =3D=3D 7); > +enum e80 { E80 =3D v79.e.x.f }; > +static_assert (E80 =3D=3D 7); > +constexpr struct s70 v81 =3D { v79 }; > +static_assert (v81.x.e.x.f =3D=3D 7); > +constexpr struct s68 v82 =3D { (constexpr struct s67) { 5, 6, 0, 0, nullp= tr, 9, { 1, 2 } } }; > +static_assert (v82.x.a =3D=3D 5); > +static_assert (v82.x.f =3D=3D 9); > +constexpr auto v83 =3D (constexpr int) { (constexpr int) { 0 } }; > +/* These are null pointers but not null pointer constants. */ > +constexpr typeof (nullptr) v84 =3D nullptr; > +constexpr void *v85 =3D 0; > +int *v86 =3D v85; > +int *v87 =3D v84; > +typeof (1 ? v85 : (int *) 0) v88; > +extern void *v88; > +typeof (1 ? (void *) 0 : (int *) 0) v89; > +extern int *v89; > +constexpr struct s68 v90 =3D { }; > +static_assert (v90.x.a =3D=3D 0); > +static_assert (v90.x.f =3D=3D 0); > +constexpr int v91 =3D { 123 }; > +static_assert (v91 =3D=3D 123); > +constexpr int v92 =3D { v91 }; > +static_assert (v92 =3D=3D 123); > +/* Verify that constexpr values can be used in various contexts requiring= > + (integer) constant expressions. */ > +struct s93 { int x : v79.e.x.f; }; > +constexpr int v94 =3D alignof (int); > +alignas (v94) int v95; > +constexpr int v97[100] =3D { [v82.x.f] =3D 7 }; > +static int v98[v94]; > + > +void > +f0 () > +{ > + constexpr int fv0 =3D 3; > + static_assert (fv0 =3D=3D 3); > + auto constexpr int fv1 =3D 4; > + static_assert (fv1 =3D=3D 4); > + register constexpr float fv2 =3D 1.0; > + constexpr auto int fv3 =3D 123; > + static_assert (fv3 =3D=3D 123); > + constexpr register void *fv4 =3D (void *) 0; > + const int *fv5 =3D &(constexpr int) { 234 }; > + const int *fv6 =3D &(constexpr static int) { 234 }; > + const int *fv7 =3D &(static constexpr int) { 234 }; > + typeof ((constexpr register int) { 234 }) *fv8; > + typeof ((register constexpr int) { 234 }) *fv9; > + int fv10 =3D (constexpr int) { 1 } + sizeof (struct fs *); > + constexpr auto fv11 =3D (constexpr int) { (constexpr int) { 0 } }; > + static_assert (fv11 =3D=3D 0); > + constexpr char fv12[3] =3D { 1, 2, 3 }; > + (constexpr short [4]) { 9, 8, 7, -6 }; > + constexpr struct s18 fv13 =3D { 1234ULL, 0, 13.0f }; > + (constexpr struct s18) { 123, (void *) 0, 11 }; > + constexpr union u20 fv14 =3D { 2 }; > + (constexpr union u20) { 5 }; > + constexpr union u20 fv15 =3D { .b =3D 15.0 }; > + (constexpr union u20) { .b =3D 20 }; > + (constexpr float) { (float) (1.0f / 3.0f) }; > + (constexpr double) { (double) (1.0 / 3.0) }; > + (constexpr struct s18) { 0, 0, (double) (1.0 / 3.0) }; > + (constexpr char []) { "abc\xfe" }; > + (constexpr unsigned char []) { u8"xyz\xff" }; > + (constexpr unsigned char []) { "\x12\x7f" }; > + (constexpr signed char []) { "\x34\x66" }; > + (constexpr double) { (int) (double) 3.0 - (long) (double) 2.0 }; > + (constexpr int) { 1 + 2 + (int) 3.0 }; > + (constexpr typeof (nullptr)) { nullptr }; > + (constexpr _Complex double) { __builtin_complex (1.0f, 3.0f / 2.0f) }; > + (constexpr float) { 1234.0L }; > + (constexpr char) { 127ULL }; > +#if FLT_MIN_EXP =3D=3D -125 && FLT_MANT_DIG =3D=3D 24 > + (constexpr float) { 0x1p-149 }; > + (constexpr float _Complex) { __builtin_complex (0x1p-149, 0x1p127) }; > + (constexpr float) { 0xffffffUL }; > + (constexpr float) { -0xffffffL }; > + (constexpr float) { 0xffffff0L }; > + (constexpr float) { 1ULL << 63 }; > +#endif > +#if DBL_MIN_EXP =3D=3D -1021 && DBL_MANT_DIG =3D=3D 53 > + (constexpr double) { 0x1p-1074L }; > + (constexpr _Complex double) { __builtin_complex (0x1p1023L, 0x1p-1074L)= }; > + (constexpr double) { 0x1fffffffffffffULL }; > + (constexpr double) { -0x1fffffffffffffLL }; > + (constexpr double) { 0x3ffffffffffffeULL }; > + (constexpr double) { 1ULL << 63 }; > +#endif > + (constexpr void *) { (void *) 0 }; > + (constexpr int *) { (void *) 0L }; > + (constexpr long *) { 0LL }; > + (constexpr int) {}; > + (constexpr float) {}; > + (constexpr long double) {}; > + (constexpr int *) {}; > + (constexpr void *) {}; > + (constexpr typeof (nullptr)) {}; > + (constexpr int *) { 0 }; > + (constexpr struct s57) { 0 }; > + (constexpr struct s57) { { } }; /* { dg-warning "braces around scalar i= nitializer" } */ > + (constexpr struct s57) { { 0 } }; /* { dg-warning "braces around scalar= initializer" } */ > + (constexpr union u58) { 0 }; > + (constexpr union u58) { { } }; /* { dg-warning "braces around scalar in= itializer" } */ > + (constexpr union u58) { { 0 } }; /* { dg-warning "braces around scalar i= nitializer" } */ > + /* It's not entirely clear if constexpr declarations are allowed in thi= s > + position in a for loop; presume they are, as implicitly auto just as= if no > + storage class specifiers were used. */ > + for (constexpr int fv16 =3D 1;;) > + break; > + constexpr struct s67 fv17 =3D { 1, 2.0, 0, 0, nullptr, 7, { 3, 4 } }; > + static_assert (fv17.a =3D=3D 1); > + static_assert (fv17.f =3D=3D 7); > + constexpr struct s67 fv18 =3D fv17; > + static_assert (fv18.a =3D=3D 1); > + static_assert (fv18.f =3D=3D 7); > + constexpr auto fv19 =3D fv17; > + static_assert (fv19.a =3D=3D 1); > + static_assert (fv19.f =3D=3D 7); > + auto fv20 =3D fv17; > + constexpr struct s68 fv21 =3D { fv18 }; > + static_assert (fv21.x.a =3D=3D 1); > + static_assert (fv21.x.f =3D=3D 7); > + constexpr union u69 fv22 =3D { }; > + static_assert (fv22.a =3D=3D 0); > + constexpr union u69 fv23 =3D { .e =3D fv21 }; > + static_assert (fv23.e.x.a =3D=3D 1); > + static_assert (fv23.e.x.f =3D=3D 7); > + constexpr union u69 fv24 =3D { .a =3D 1 }; > + static_assert (fv24.a =3D=3D 1); > + constexpr union u69 fv25 =3D { .e =3D { fv18 } }; > + static_assert (fv25.e.x.a =3D=3D 1); > + static_assert (fv25.e.x.f =3D=3D 7); > + enum fe80 { FE80 =3D fv25.e.x.f }; > + static_assert (FE80 =3D=3D 7); > + constexpr struct s70 fv26 =3D { fv25 }; > + static_assert (fv26.x.e.x.f =3D=3D 7); > + constexpr struct s68 fv27 =3D { (constexpr struct s67) { 5, 6, 0, 0, nu= llptr, 9, { 1, 2 } } }; > + static_assert (fv27.x.a =3D=3D 5); > + static_assert (fv27.x.f =3D=3D 9); > + constexpr struct s68 fv28 =3D { }; > + static_assert (fv28.x.a =3D=3D 0); > + static_assert (fv28.x.f =3D=3D 0); > + constexpr int fv29 =3D { 123 }; > + static_assert (fv29 =3D=3D 123); > + constexpr int fv30 =3D { fv29 }; > + static_assert (fv30 =3D=3D 123); > + static_assert ((constexpr struct s67) { 1, 2.0, 0, 0, nullptr, 7, { 3, 4= } }.f =3D=3D 7); > + static_assert ((constexpr struct s68) { fv18 }.x.a =3D=3D 1); > + static_assert ((constexpr union u69) { }.a =3D=3D 0); > + static_assert ((constexpr union u69) { .e =3D fv21 }.e.x.f =3D=3D 7); > + static_assert ((constexpr union u69) { .a =3D 1 }.a =3D=3D 1); > + static_assert ((constexpr union u69) { .e =3D { fv18 } }.e.x.a =3D=3D 1= ); > + static_assert ((constexpr struct s70) { fv25 }.x.e.x.f =3D=3D 7); > + static_assert ((constexpr struct s68) { (constexpr struct s67) { 5, 6, 0= , 0, nullptr, 9, { 1, 2 } } }.x.f =3D=3D 9); > + static_assert ((constexpr struct s68) { }.x.f =3D=3D 0); > + /* Verify that constexpr values can be used in various contexts requiri= ng > + (integer) constant expressions. */ > + struct fs93 { int x : fv25.e.x.f; }; > + constexpr int fv31 =3D alignof (int); > + alignas (fv31) int fv32; > + constexpr int fv33[100] =3D { [fv27.x.f] =3D 7 }; > + static int fv34[fv31]; > + switch (fv0) > + { > + case fv27.x.f: ; > + } > +} > diff --git a/gcc/testsuite/gcc.dg/c2x-constexpr-2a.c b/gcc/testsuite/gcc.d= g/c2x-constexpr-2a.c > new file mode 100644 > index 00000000000..f74e2ec53bb > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/c2x-constexpr-2a.c > @@ -0,0 +1,37 @@ > +/* Test C2x constexpr. Valid code, execution test. */ > +/* { dg-do link } */ > +/* { dg-options "-std=3Dc2x -pedantic-errors" } */ > +/* { dg-additional-sources "c2x-constexpr-2b.c" } */ > + > +extern void abort (void); > +extern void exit (int); > + > +/* constexpr objects at file scope have internal linkage. */ > +constexpr int a =3D 2; > + > +struct s { int a; float b; int c[3]; }; > +constexpr struct s s1 =3D { 2, 3, { 4, 5, 6 } }; > +constexpr struct s s2 =3D s1; > +struct s s3 =3D s2; > + > +void > +check (const struct s *p) > +{ > + if (p->a !=3D 2 || p->b !=3D 3 || p->c[0] !=3D 4 || p->c[1] !=3D 5 || p= ->c[2] !=3D 6) > + abort (); > +} > + > +int > +main () > +{ > + constexpr struct s s4 =3D s1; > + struct s s5 =3D s4; > + constexpr struct s s6 =3D { s1.a, s2.b, { 4, 5, 6 } }; > + check (&s1); > + check (&s2); > + check (&s3); > + check (&s4); > + check (&s5); > + check (&s6); > + exit (0); > +} > diff --git a/gcc/testsuite/gcc.dg/c2x-constexpr-2b.c b/gcc/testsuite/gcc.d= g/c2x-constexpr-2b.c > new file mode 100644 > index 00000000000..04058b3f559 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/c2x-constexpr-2b.c > @@ -0,0 +1,6 @@ > +/* Test C2x constexpr. Second file for link test. */ > +/* { dg-do compile } */ > +/* { dg-options "-std=3Dc2x -pedantic-errors" } */ > + > +/* constexpr objects at file scope have internal linkage. */ > +constexpr int a =3D 3; > diff --git a/gcc/testsuite/gcc.dg/c2x-constexpr-3.c b/gcc/testsuite/gcc.dg= /c2x-constexpr-3.c > new file mode 100644 > index 00000000000..16e56db2835 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/c2x-constexpr-3.c > @@ -0,0 +1,228 @@ > +/* Test C2x constexpr. Invalid code. */ > +/* { dg-do compile } */ > +/* { dg-options "-std=3Dc2x -pedantic-errors" } */ > + > +extern constexpr int v0 =3D 0; /* { dg-error "'constexpr' used with 'exte= rn'" } */ > +/* { dg-warning "initialized and declared 'extern'" "initialized extern" {= target *-*-* } .-1 } */ > +constexpr extern int v1 =3D 0; /* { dg-error "'constexpr' used with 'exte= rn'" } */ > +/* { dg-warning "initialized and declared 'extern'" "initialized extern" {= target *-*-* } .-1 } */ > +typedef constexpr int v2; /* { dg-error "'constexpr' used with 'typedef'"= } */ > +constexpr typedef int v3; /* { dg-error "'constexpr' used with 'typedef'"= } */ > +thread_local constexpr int v4 =3D 0; /* { dg-error "'constexpr' used with= '_Thread_local'" } */ > +constexpr thread_local int v5 =3D 0; /* { dg-error "'thread_local' used w= ith 'constexpr'" } */ > +constexpr constexpr int v6 =3D 1; /* { dg-error "duplicate 'constexpr'" }= */ > +constexpr struct v7; /* { dg-error "'constexpr' in empty declaration" } *= / > +/* { dg-error "'struct v7' declared in underspecified object declaration"= "underspecified" { target *-*-* } .-1 } */ > +constexpr union v8; /* { dg-error "'constexpr' in empty declaration" } */= > +/* { dg-error "'union v8' declared in underspecified object declaration" "= underspecified" { target *-*-* } .-1 } */ > +constexpr struct v9 { int a; }; /* { dg-error "'constexpr' in empty decla= ration" } */ > +/* { dg-error "'struct v9' defined in underspecified object declaration" "= underspecified" { target *-*-* } .-1 } */ > +constexpr union v10 { int a; }; /* { dg-error "'constexpr' in empty decla= ration" } */ > +/* { dg-error "'union v10' defined in underspecified object declaration" "= underspecified" { target *-*-* } .-1 } */ > +constexpr; /* { dg-error "'constexpr' in empty declaration" } */ > +constexpr int; /* { dg-error "empty declaration" } */ > +constexpr const; /* { dg-error "empty declaration" } */ > +constexpr int v11; /* { dg-error "initialized data declaration" } */ > +constexpr int v12 { } /* { dg-error "initialized data declaration" } */ > +constexpr int v13 =3D 1, v14 =3D 2; /* { dg-error "single declarator" } *= / > +constexpr int v15 =3D sizeof (struct v16 *); /* { dg-error "declared in u= nderspecified object initializer" } */ > +constexpr int v17 =3D sizeof (union v18 *); /* { dg-error "declared in un= derspecified object initializer" } */ > +constexpr int v19 =3D sizeof (struct v20 { int a; }); /* { dg-error "defi= ned in underspecified object initializer" } */ > +constexpr int v21 =3D sizeof (struct { int a; }); /* { dg-error "defined i= n underspecified object initializer" } */ > +constexpr int v22 =3D sizeof (union v23 { int a; }); /* { dg-error "defin= ed in underspecified object initializer" } */ > +constexpr int v24 =3D sizeof (union { int a; }); /* { dg-error "defined i= n underspecified object initializer" } */ > +constexpr int v25 =3D sizeof (enum v26 { A }); /* { dg-error "defined in u= nderspecified object initializer" } */ > +/* The following case is undefined behavior (so doesn't actually require a= > + diagnostic). */ > +constexpr int v27 =3D sizeof (enum { B }); /* { dg-error "defined in unde= rspecified object initializer" } */ > +/* Examples with a forward declaration, then definition inside constexpr.= */ > +struct v28; > +constexpr int v29 =3D sizeof (struct v28 { int a; }); /* { dg-error "defi= ned in underspecified object initializer" } */ > +union v30; > +constexpr int v31 =3D sizeof (union v30 { int a; }); /* { dg-error "defin= ed in underspecified object initializer" } */ > +constexpr int v32 =3D sizeof (v32); /* { dg-error "underspecified 'v32' r= eferenced in its initializer" } */ > +static const int v33; > +constexpr const int v33 =3D 1; /* { dg-error "underspecified declaration o= f 'v33', which is already declared in this scope" } */ > +constexpr void v34 () {} /* { dg-error "'constexpr' requires an initializ= ed data declaration" } */ > +void v35 (constexpr int v36); /* { dg-error "storage class specified for p= arameter 'v36'" } */ > +void v37 (constexpr short); /* { dg-error "storage class specified for un= named parameter" } */ > +void v38 (constexpr register int v39); /* { dg-error "storage class speci= fied for parameter 'v39'" } */ > +void v40 (constexpr register short); /* { dg-error "storage class specifi= ed for unnamed parameter" } */ > +/* The following case is undefined behavior (presumably to allow for poss= ible > + future support for constexpr functions), but should clearly be diagnos= ed > + when such functions aren't actually supported. */ > +constexpr int v41 (); /* { dg-error "'constexpr' requires an initialized d= ata declaration" } */ > +typedef volatile long t42; > +typedef int *restrict t43; > +typedef _Atomic int t44; > +struct t45 { struct { struct { t42 a[2]; } a; } a; }; > +struct t46 { struct { struct { int z; int *restrict a; } a[3]; } a; }; > +struct t47 { short x; struct { struct { _Atomic long a; } a; } a[4][5]; }= ; > +constexpr t42 v48 =3D {}; /* { dg-error "invalid qualifiers for 'constexp= r' object" } */ > +constexpr t43 v49 =3D {}; /* { dg-error "invalid qualifiers for 'constexp= r' object" } */ > +constexpr t44 v50 =3D {}; /* { dg-error "invalid qualifiers for 'constexp= r' object" } */ > +constexpr volatile double v51 =3D {}; /* { dg-error "invalid qualifiers f= or 'constexpr' object" } */ > +constexpr int *restrict v52 =3D {}; /* { dg-error "invalid qualifiers for= 'constexpr' object" } */ > +constexpr _Atomic (short) v53 =3D {}; /* { dg-error "invalid qualifiers f= or 'constexpr' object" } */ > +constexpr long *volatile v54 =3D {}; /* { dg-error "invalid qualifiers fo= r 'constexpr' object" } */ > +constexpr struct t45 v55 =3D {}; /* { dg-error "invalid qualifiers for fi= eld of 'constexpr' object" } */ > +constexpr struct t46 v56 =3D {}; /* { dg-error "invalid qualifiers for fi= eld of 'constexpr' object" } */ > +constexpr struct t47 v57 =3D {}; /* { dg-error "invalid qualifiers for fi= eld of 'constexpr' object" } */ > +union t58 { struct { union { t42 a[1]; } a; } a; }; > +union t59 { struct { union { int z; int *restrict a; } a; } a; }; > +union t60 { short x; union { struct { _Atomic long a; } a[3]; } a; }; > +constexpr union t58 v61 =3D {}; /* { dg-error "invalid qualifiers for fie= ld of 'constexpr' object" } */ > +constexpr union t59 v62 =3D {}; /* { dg-error "invalid qualifiers for fie= ld of 'constexpr' object" } */ > +constexpr union t60 v63 =3D {}; /* { dg-error "invalid qualifiers for fie= ld of 'constexpr' object" } */ > +constexpr t42 v64[1][2][3] =3D {}; /* { dg-error "invalid qualifiers for '= constexpr' object" } */ > +constexpr volatile int v65[1][2][3] =3D {}; /* { dg-error "invalid qualif= iers for 'constexpr' object" } */ > +constexpr struct t45 v66[2][2][4] =3D {}; /* { dg-error "invalid qualifie= rs for field of 'constexpr' object" } */ > +constexpr union t60 v67[2][2][4] =3D {}; /* { dg-error "invalid qualifier= s for field of 'constexpr' object" } */ > +int v68 =3D 0; > +constexpr int v69 =3D v68; /* { dg-error "initializer element is not cons= tant" } */ > +double exp (double); > +constexpr double v70 =3D exp (0); /* { dg-error "initializer element is n= ot a constant expression" } */ > +struct s71 { int a; double b; }; > +constexpr struct s71 v72 =3D { 0, exp (0) }; /* { dg-error "initializer e= lement is not a constant expression" } */ > +/* { dg-error "'constexpr' initializer is not an arithmetic constant expr= ession" "arithmetic" { target *-*-* } .-1 } */ > +constexpr struct s71 v73 =3D { v68, 0 }; /* { dg-error "initializer eleme= nt is not constant" } */ > +union u74 { int a; double b; }; > +constexpr union u74 v75 =3D { v68 }; /* { dg-error "initializer element i= s not constant" } */ > +constexpr union u74 v76 =3D { .b =3D exp (0) }; /* { dg-error "initialize= r element is not a constant expression" } */ > +/* { dg-error "'constexpr' initializer is not an arithmetic constant expr= ession" "arithmetic" { target *-*-* } .-1 } */ > +constexpr struct s77 *v77 =3D 0; /* { dg-error "'struct s77' declared in u= nderspecified object declaration" } */ > +constexpr union u78 *v78 =3D 0; /* { dg-error "'union u78' declared in un= derspecified object declaration" } */ > +constexpr struct s79 { int a; } v79 =3D { 0 }; /* { dg-error "'struct s79= ' defined in underspecified object declaration" } */ > +constexpr union u80 { int a; } v80 =3D { 0 }; /* { dg-error "'union u80' d= efined in underspecified object declaration" } */ > +constexpr enum e81 { E81 } v81 =3D E81; /* { dg-error "'enum e81' defined= in underspecified object declaration" } */ > +constexpr enum { E82 } v82 =3D E82; /* { dg-error "defined in underspecif= ied object declaration" } */ > +struct s83 constexpr *v83 =3D 0; /* { dg-error "'struct s83' declared in u= nderspecified object declaration" } */ > +union u84 constexpr *v84 =3D 0; /* { dg-error "'union u84' declared in un= derspecified object declaration" } */ > +struct s85 { int a; } constexpr v85 =3D { 0 }; /* { dg-error "'struct s85= ' defined in underspecified object declaration" } */ > +union u86 { int a; } constexpr v86 =3D { 0 }; /* { dg-error "'union u86' d= efined in underspecified object declaration" } */ > +enum e87 { E87 } constexpr v87 =3D E87; /* { dg-error "'enum e87' defined= in underspecified object declaration" } */ > +enum { E88 } constexpr v88 =3D E88; /* { dg-error "defined in underspecif= ied object declaration" } */ > +constexpr int *v89 =3D (int *) 0; /* { dg-error "'constexpr' pointer init= ializer is not a null pointer constant" } */ > +constexpr void *v90 =3D (void *) (void *) 0; /* { dg-error "'constexpr' p= ointer initializer is not a null pointer constant" } */ > +constexpr int v91 =3D (int) (double) 1.0; /* { dg-error "constexpr' integ= er initializer is not an integer constant expression" } */ > +constexpr struct s71 v92 =3D { (int) (double) 1.0, 0 }; /* { dg-error "co= nstexpr' integer initializer is not an integer constant expression" } */ > +struct s93 { void *p; }; > +constexpr struct s93 v94 =3D { (int *) 0 }; /* { dg-error "'constexpr' po= inter initializer is not a null pointer constant" } */ > +constexpr int v95 =3D (unsigned int) -1; /* { dg-error "'constexpr' initi= alizer not representable in type of object" } */ > +constexpr unsigned char v96 =3D -1; /* { dg-error "'constexpr' initialize= r not representable in type of object" } */ > +constexpr signed char v97 =3D 1234567LL; /* { dg-error "'constexpr' initi= alizer not representable in type of object" } */ > +/* { dg-warning "overflow in conversion" "overflow warning" { target *-*-= * } .-1 } */ > +/* Disallow all real/complex conversions (the C2x CD is unclear about > + real-to-complex and about complex-to-real with imaginary part positive= 0, if > + the real parts can be exactly represented in the relevant types). */ > +constexpr double v98 =3D __builtin_complex (1.0, 0.0); /* { dg-error "'co= nstexpr' initializer for a real type is of complex type" } */ > +constexpr double v99 =3D __builtin_complex (1.0, 1.0); /* { dg-error "'co= nstexpr' initializer for a real type is of complex type" } */ > +constexpr double v100 =3D __builtin_complex (1.0, -0.0); /* { dg-error "'= constexpr' initializer for a real type is of complex type" } */ > +constexpr _Complex double v101 =3D 1.0; /* { dg-error "'constexpr' initia= lizer for a complex type is of real type" } */ > +constexpr float v102 =3D (unsigned long long) -1; /* { dg-error "'constex= pr' initializer not representable in type of object" } */ > +constexpr double v103 =3D (unsigned long long) -1; /* { dg-error "'conste= xpr' initializer not representable in type of object" } */ > +constexpr float v104 =3D __LONG_LONG_MAX__; /* { dg-error "'constexpr' in= itializer not representable in type of object" } */ > +constexpr double v105 =3D __LONG_LONG_MAX__; /* { dg-error "'constexpr' i= nitializer not representable in type of object" } */ > +constexpr signed char v106[] =3D u8"\xff"; /* { dg-error "'constexpr' ini= tializer not representable in type of object" } */ > +/* Only the initialized (possibly by default) element of a constexpr unio= n is a > + named constant. */ > +union u107 { int a; int b; }; > +constexpr union u107 v108 =3D { }; > +constexpr union u107 v109 =3D { .a =3D 0 }; > +constexpr union u107 v110 =3D { .b =3D 0 }; > +constexpr int v111 =3D v108.b; /* { dg-error "initializer" } */ > +constexpr int v112 =3D v109.b; /* { dg-error "initializer" } */ > +constexpr int v113 =3D v110.a; /* { dg-error "initializer" } */ > +/* A reference to an array in a constexpr object is converted to a pointe= r as > + usual, so in particular is not equivalent to directly using a string l= iteral > + initializer extracted from the initializer of that object. */ > +struct s114 { char c[10]; }; > +constexpr struct s114 v115 =3D { "abc" }; > +constexpr struct s114 v116 =3D { v115.c }; /* { dg-error "initializer" } *= / > +/* { dg-error "integer from pointer" "conversion" { target *-*-* } .-1 } *= / > + > +void > +f0 () > +{ > + (constexpr constexpr int) { 1 }; /* { dg-error "duplicate 'constexpr'" }= */ > + (constexpr thread_local int) { 1 }; /* { dg-error "'thread_local' used w= ith 'constexpr'" } */ > + (thread_local constexpr static int) { 1 }; /* { dg-error "'constexpr' u= sed with '_Thread_local'" } */ > + (constexpr int) { sizeof (struct fs1 *) }; /* { dg-error "declared in u= nderspecified object initializer" } */ > + (constexpr int) { sizeof (union fs2 *) }; /* { dg-error "declared in un= derspecified object initializer" } */ > + (constexpr int) { sizeof (struct fs3 { int a; }) }; /* { dg-error "defi= ned in underspecified object initializer" } */ > + (constexpr int) { sizeof (struct { int a; }) }; /* { dg-error "defined i= n underspecified object initializer" } */ > + (constexpr int) { sizeof (union fs4 { int a; }) }; /* { dg-error "defin= ed in underspecified object initializer" } */ > + (constexpr int) { sizeof (union { int a; }) }; /* { dg-error "defined i= n underspecified object initializer" } */ > + (constexpr int) { sizeof (enum fs5 { A }) }; /* { dg-error "defined in u= nderspecified object initializer" } */ > + /* The following case is undefined behavior (so doesn't actually requir= e a > + diagnostic). */ > + (constexpr int) { sizeof (enum { B }) }; /* { dg-error "defined in unde= rspecified object initializer" } */ > + /* Examples with a forward declaration, then definition inside constexp= r. */ > + struct fs6; > + (constexpr int) { sizeof (struct fs6 { int a; }) }; /* { dg-error "defi= ned in underspecified object initializer" } */ > + union fs7; > + (constexpr int) { sizeof (union fs7 { int a; }) }; /* { dg-error "defin= ed in underspecified object initializer" } */ > + constexpr int fv32 =3D sizeof (fv32); /* { dg-error "underspecified 'fv= 32' referenced in its initializer" } */ > + /* Test entering then exiting nested underspecified initializers. */ > + constexpr int x =3D (constexpr int) { 1 } + sizeof (struct fs8 *); /* {= dg-error "declared in underspecified object initializer" } */ > + auto y =3D (constexpr int) { 1 } + sizeof (struct fs9 *); /* { dg-error= "declared in underspecified object initializer" } */ > + extern const int z; /* { dg-message "previous declaration" } */ > + constexpr const int z =3D 1; /* { dg-error "underspecified declaration o= f 'z', which is already declared in this scope" } */ > + /* { dg-error "declaration of 'z' with no linkage follows extern declar= ation" "linkage error" { target *-*-* } .-1 } */ > + int non_const =3D 1; > + typedef int VLA[non_const]; > + constexpr VLA *pnc =3D nullptr; /* { dg-error "'constexpr' object has v= ariably modified type" } */ > + (constexpr t42) {}; /* { dg-error "invalid qualifiers for 'constexpr' o= bject" } */ > + (constexpr t43) {}; /* { dg-error "invalid qualifiers for 'constexpr' o= bject" } */ > + (constexpr t44) {}; /* { dg-error "invalid qualifiers for 'constexpr' o= bject" } */ > + (constexpr volatile double) {}; /* { dg-error "invalid qualifiers for '= constexpr' object" } */ > + (constexpr int *restrict) {}; /* { dg-error "invalid qualifiers for 'co= nstexpr' object" } */ > + (constexpr _Atomic (short)) {}; /* { dg-error "invalid qualifiers for '= constexpr' object" } */ > + (constexpr long *volatile) {}; /* { dg-error "invalid qualifiers for 'c= onstexpr' object" } */ > + (constexpr struct t45) {}; /* { dg-error "invalid qualifiers for field o= f 'constexpr' object" } */ > + (constexpr struct t46) {}; /* { dg-error "invalid qualifiers for field o= f 'constexpr' object" } */ > + (constexpr struct t47) {}; /* { dg-error "invalid qualifiers for field o= f 'constexpr' object" } */ > + (constexpr union t58) {}; /* { dg-error "invalid qualifiers for field o= f 'constexpr' object" } */ > + (constexpr union t59) {}; /* { dg-error "invalid qualifiers for field o= f 'constexpr' object" } */ > + (constexpr union t60) {}; /* { dg-error "invalid qualifiers for field o= f 'constexpr' object" } */ > + (constexpr t42 [1][2][3]) {}; /* { dg-error "invalid qualifiers for 'co= nstexpr' object" } */ > + (constexpr volatile int [1][2][3]) {}; /* { dg-error "invalid qualifier= s for 'constexpr' object" } */ > + (constexpr struct t45 [2][2][4]) {}; /* { dg-error "invalid qualifiers f= or field of 'constexpr' object" } */ > + (constexpr union t60 [2][2][4]) {}; /* { dg-error "invalid qualifiers f= or field of 'constexpr' object" } */ > + (constexpr int) { v68 }; /* { dg-error "initializer element is not cons= tant" } */ > + (constexpr double) { exp (0) }; /* { dg-error "initializer element is n= ot a constant expression" } */ > + /* { dg-error "'constexpr' initializer is not an arithmetic constant ex= pression" "arithmetic" { target *-*-* } .-1 } */ > + (constexpr struct s71) { 0, exp (0) }; /* { dg-error "initializer eleme= nt is not a constant expression" } */ > + /* { dg-error "'constexpr' initializer is not an arithmetic constant ex= pression" "arithmetic" { target *-*-* } .-1 } */ > + (constexpr struct s71) { v68, 0 }; /* { dg-error "initializer element i= s not constant" } */ > + (constexpr union u74) { v68 }; /* { dg-error "initializer element is no= t constant" } */ > + (constexpr union u74) { .b =3D exp (0) }; /* { dg-error "initializer el= ement is not a constant expression" } */ > + /* { dg-error "'constexpr' initializer is not an arithmetic constant ex= pression" "arithmetic" { target *-*-* } .-1 } */ > + (constexpr struct fs10 *) { 0 }; /* { dg-error "declared in 'constexpr'= compound literal" } */ > + (constexpr union fs11 *) { 0 }; /* { dg-error "declared in 'constexpr' c= ompound literal" } */ > + (constexpr struct fs12 { int a; }) { 0 }; /* { dg-error "defined in 'co= nstexpr' compound literal" } */ > + (constexpr union fs13 { int a; }) { 0 }; /* { dg-error "defined in 'con= stexpr' compound literal" } */ > + (constexpr enum fs14 { FS14 }) { FS14 }; /* { dg-error "defined in 'con= stexpr' compound literal" } */ > + (constexpr enum { FS15 }) { FS15 }; /* { dg-error "defined in 'constexp= r' compound literal" } */ > + (constexpr int *) { (int *) 0 }; /* { dg-error "'constexpr' pointer ini= tializer is not a null pointer constant" } */ > + (constexpr void *) { (void *) (void *) 0 }; /* { dg-error "'constexpr' p= ointer initializer is not a null pointer constant" } */ > + (constexpr int) { (int) (double) 1.0 }; /* { dg-error "constexpr' integ= er initializer is not an integer constant expression" } */ > + (constexpr struct s71) { (int) (double) 1.0, 0 }; /* { dg-error "conste= xpr' integer initializer is not an integer constant expression" } */ > + (constexpr struct s93) { (int *) 0 }; /* { dg-error "'constexpr' pointe= r initializer is not a null pointer constant" } */ > + (constexpr int) { (unsigned int) -1 }; /* { dg-error "'constexpr' initi= alizer not representable in type of object" } */ > + (constexpr unsigned char) { -1 }; /* { dg-error "'constexpr' initialize= r not representable in type of object" } */ > + (constexpr signed char) { 1234567LL }; /* { dg-error "'constexpr' initi= alizer not representable in type of object" } */ > + /* { dg-warning "overflow in conversion" "overflow warning" { target *-= *-* } .-1 } */ > + (constexpr double) { __builtin_complex (1.0, 0.0) }; /* { dg-error "'co= nstexpr' initializer for a real type is of complex type" } */ > + (constexpr double) { __builtin_complex (1.0, 1.0) }; /* { dg-error "'co= nstexpr' initializer for a real type is of complex type" } */ > + (constexpr double) { __builtin_complex (1.0, -0.0) }; /* { dg-error "'c= onstexpr' initializer for a real type is of complex type" } */ > + (constexpr _Complex double) { 1.0 }; /* { dg-error "'constexpr' initial= izer for a complex type is of real type" } */ > + (constexpr float) { (unsigned long long) -1 }; /* { dg-error "'constexp= r' initializer not representable in type of object" } */ > + (constexpr double) { (unsigned long long) -1 }; /* { dg-error "'constex= pr' initializer not representable in type of object" } */ > + (constexpr float) { __LONG_LONG_MAX__ }; /* { dg-error "'constexpr' ini= tializer not representable in type of object" } */ > + (constexpr double) { __LONG_LONG_MAX__ }; /* { dg-error "'constexpr' in= itializer not representable in type of object" } */ > + (constexpr signed char []) { u8"\xff" }; /* { dg-error "'constexpr' ini= tializer not representable in type of object" } */ > + constexpr typeof (nullptr) not_npc =3D nullptr; > + int *ptr =3D 0; > + (void) (ptr =3D=3D not_npc); /* { dg-error "invalid operands" } */ > +} > diff --git a/gcc/testsuite/gcc.dg/c2x-constexpr-4.c b/gcc/testsuite/gcc.dg= /c2x-constexpr-4.c > new file mode 100644 > index 00000000000..2a42af890a2 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/c2x-constexpr-4.c > @@ -0,0 +1,21 @@ > +/* Test C2x constexpr. Valid code, compilation tests, signed char. */ > +/* { dg-do compile } */ > +/* { dg-options "-std=3Dc2x -pedantic-errors -fsigned-char" } */ > + > +constexpr char v1[] =3D "\x00\xff"; > +constexpr signed char v2[] =3D "\x7f\x80"; > +constexpr unsigned char v3[] =3D "\x00\x7f"; > +constexpr char v4[] =3D u8"\x00\x7f"; > +constexpr signed char v5[] =3D u8"\x7f\x00"; > +constexpr unsigned char v6[] =3D u8"\x00\xff"; > + > +void > +f0 () > +{ > + (constexpr char []) { "\x00\xff" }; > + (constexpr signed char []) { "\x7f\x80" }; > + (constexpr unsigned char []) { "\x00\x7f" }; > + (constexpr char []) { u8"\x00\x7f" }; > + (constexpr signed char []) { u8"\x7f\x00" }; > + (constexpr unsigned char []) { u8"\x00\xff" }; > +} > diff --git a/gcc/testsuite/gcc.dg/c2x-constexpr-5.c b/gcc/testsuite/gcc.dg= /c2x-constexpr-5.c > new file mode 100644 > index 00000000000..6febd2ee67f > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/c2x-constexpr-5.c > @@ -0,0 +1,21 @@ > +/* Test C2x constexpr. Valid code, compilation tests, unsigned char. */= > +/* { dg-do compile } */ > +/* { dg-options "-std=3Dc2x -pedantic-errors -funsigned-char" } */ > + > +constexpr char v1[] =3D "\x00\xff"; > +constexpr signed char v2[] =3D "\x7f\x00"; > +constexpr unsigned char v3[] =3D "\x80\x7f"; > +constexpr char v4[] =3D u8"\x00\xff"; > +constexpr signed char v5[] =3D u8"\x7f\x00"; > +constexpr unsigned char v6[] =3D u8"\x00\xff"; > + > +void > +f0 () > +{ > + (constexpr char []) { "\x00\xff" }; > + (constexpr signed char []) { "\x7f\x00" }; > + (constexpr unsigned char []) { "\x80\x7f" }; > + (constexpr char []) { u8"\x00\xff" }; > + (constexpr signed char []) { u8"\x7f\x00" }; > + (constexpr unsigned char []) { u8"\x00\xff" }; > +} > diff --git a/gcc/testsuite/gcc.dg/c2x-constexpr-6.c b/gcc/testsuite/gcc.dg= /c2x-constexpr-6.c > new file mode 100644 > index 00000000000..a86124a9974 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/c2x-constexpr-6.c > @@ -0,0 +1,15 @@ > +/* Test C2x constexpr. Invalid code, compilation tests, signed char. */= > +/* { dg-do compile } */ > +/* { dg-options "-std=3Dc2x -pedantic-errors -fsigned-char" } */ > + > +constexpr unsigned char v3[] =3D "\x00\xff"; /* { dg-error "'constexpr' i= nitializer not representable in type of object" } */ > +constexpr char v4[] =3D u8"\x00\xff"; /* { dg-error "'constexpr' initiali= zer not representable in type of object" } */ > +constexpr signed char v5[] =3D u8"\x00\xff"; /* { dg-error "'constexpr' i= nitializer not representable in type of object" } */ > + > +void > +f0 () > +{ > + (constexpr unsigned char []) { "\x00\xff" }; /* { dg-error "'constexpr'= initializer not representable in type of object" } */ > + (constexpr char []) { u8"\x00\xff" }; /* { dg-error "'constexpr' initia= lizer not representable in type of object" } */ > + (constexpr signed char []) { u8"\x00\xff" }; /* { dg-error "'constexpr'= initializer not representable in type of object" } */ > +} > diff --git a/gcc/testsuite/gcc.dg/c2x-constexpr-7.c b/gcc/testsuite/gcc.dg= /c2x-constexpr-7.c > new file mode 100644 > index 00000000000..5282d923182 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/c2x-constexpr-7.c > @@ -0,0 +1,13 @@ > +/* Test C2x constexpr. Invalid code, compilation tests, unsigned char. *= / > +/* { dg-do compile } */ > +/* { dg-options "-std=3Dc2x -pedantic-errors -funsigned-char" } */ > + > +constexpr signed char v2[] =3D "\x00\xff"; /* { dg-error "'constexpr' ini= tializer not representable in type of object" } */ > +constexpr signed char v5[] =3D u8"\x00\xff"; /* { dg-error "'constexpr' i= nitializer not representable in type of object" } */ > + > +void > +f0 () > +{ > + (constexpr signed char []) { "\x00\xff" }; /* { dg-error "'constexpr' i= nitializer not representable in type of object" } */ > + (constexpr signed char []) { u8"\x00\xff" }; /* { dg-error "'constexpr'= initializer not representable in type of object" } */ > +} > diff --git a/gcc/testsuite/gcc.dg/c2x-constexpr-8.c b/gcc/testsuite/gcc.dg= /c2x-constexpr-8.c > new file mode 100644 > index 00000000000..c7119c97a69 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/c2x-constexpr-8.c > @@ -0,0 +1,23 @@ > +/* Test C2x constexpr. Valid code, compilation tests, IEEE arithmetic. *= / > +/* { dg-do compile } */ > +/* { dg-options "-std=3Dc2x -pedantic-errors" } */ > +/* { dg-add-options ieee } */ > +/* { dg-require-effective-target inff } */ > + > +constexpr float fi =3D __builtin_inf (); > +constexpr double di =3D __builtin_inff (); > +constexpr float fn =3D __builtin_nan (""); > +constexpr double dn =3D __builtin_nanf (""); > +constexpr float fns =3D __builtin_nansf (""); > +constexpr double dns =3D __builtin_nans (""); > + > +void > +f0 (void) > +{ > + (constexpr float) { __builtin_inf () }; > + (constexpr double) { __builtin_inff () }; > + (constexpr float) { __builtin_nan ("") }; > + (constexpr double) { __builtin_nanf ("") }; > + (constexpr float) { __builtin_nansf ("") }; > + (constexpr double) { __builtin_nans ("") }; > +} > diff --git a/gcc/testsuite/gcc.dg/c2x-constexpr-9.c b/gcc/testsuite/gcc.dg= /c2x-constexpr-9.c > new file mode 100644 > index 00000000000..c62fc738fa0 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/c2x-constexpr-9.c > @@ -0,0 +1,39 @@ > +/* Test C2x constexpr. Invalid code, compilation tests, IEEE arithmetic.= */ > +/* { dg-do compile } */ > +/* { dg-options "-std=3Dc2x -pedantic-errors" } */ > +/* { dg-add-options ieee } */ > +/* { dg-require-effective-target inff } */ > + > +/* A conversion from signaling NaN to quiet NaN in a different format is n= ot > + valid for constexpr. */ > +constexpr float fns =3D __builtin_nans (""); /* { dg-error "'constexpr' i= nitializer not representable in type of object" } */ > +constexpr double dns =3D __builtin_nansf (""); /* { dg-error "'constexpr'= initializer not representable in type of object" } */ > + > +/* Test out-of-range values. */ > +constexpr float fu =3D __DBL_MIN__; /* { dg-error "'constexpr' initialize= r not representable in type of object" } */ > +constexpr float fo =3D __DBL_MAX__; /* { dg-error "'constexpr' initialize= r not representable in type of object" } */ > +constexpr float fp =3D 0x1.ffffffp0; /* { dg-error "'constexpr' initializ= er not representable in type of object" } */ > + > +constexpr _Complex float cfur =3D __builtin_complex (__DBL_MIN__, 0.0); /= * { dg-error "'constexpr' initializer not representable in type of object" }= */ > +constexpr _Complex float cfor =3D __builtin_complex (__DBL_MAX__, 0.0); /= * { dg-error "'constexpr' initializer not representable in type of object" }= */ > +constexpr _Complex float cfpr =3D __builtin_complex (0x1.ffffffp0, 0.0); /= * { dg-error "'constexpr' initializer not representable in type of object" }= */ > + > +constexpr _Complex float cfui =3D __builtin_complex (0.0, __DBL_MIN__); /= * { dg-error "'constexpr' initializer not representable in type of object" }= */ > +constexpr _Complex float cfoi =3D __builtin_complex (0.0, __DBL_MAX__); /= * { dg-error "'constexpr' initializer not representable in type of object" }= */ > +constexpr _Complex float cfpi =3D __builtin_complex (0.0, 0x1.ffffffp0); /= * { dg-error "'constexpr' initializer not representable in type of object" }= */ > + > +void > +f0 () > +{ > + (constexpr float) { __builtin_nans ("") }; /* { dg-error "'constexpr' i= nitializer not representable in type of object" } */ > + (constexpr double) { __builtin_nansf ("") }; /* { dg-error "'constexpr'= initializer not representable in type of object" } */ > + (constexpr float) { __DBL_MIN__ }; /* { dg-error "'constexpr' initializ= er not representable in type of object" } */ > + (constexpr float) { __DBL_MAX__ }; /* { dg-error "'constexpr' initializ= er not representable in type of object" } */ > + (constexpr float) { 0x1.ffffffp0 }; /* { dg-error "'constexpr' initiali= zer not representable in type of object" } */ > + (constexpr _Complex float) { __builtin_complex (__DBL_MIN__, 0.0) }; /*= { dg-error "'constexpr' initializer not representable in type of object" } *= / > + (constexpr _Complex float) { __builtin_complex (__DBL_MAX__, 0.0) }; /*= { dg-error "'constexpr' initializer not representable in type of object" } *= / > + (constexpr _Complex float) { __builtin_complex (0x1.ffffffp0, 0.0) }; /= * { dg-error "'constexpr' initializer not representable in type of object" }= */ > + (constexpr _Complex float) { __builtin_complex (0.0, __DBL_MIN__) }; /*= { dg-error "'constexpr' initializer not representable in type of object" } *= / > + (constexpr _Complex float) { __builtin_complex (0.0, __DBL_MAX__) }; /*= { dg-error "'constexpr' initializer not representable in type of object" } *= / > + (constexpr _Complex float) { __builtin_complex (0.0, 0x1.ffffffp0) }; /= * { dg-error "'constexpr' initializer not representable in type of object" }= */ > +} > diff --git a/gcc/testsuite/gcc.dg/dfp/c2x-constexpr-dfp-1.c b/gcc/testsuit= e/gcc.dg/dfp/c2x-constexpr-dfp-1.c > new file mode 100644 > index 00000000000..568f1428b40 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/dfp/c2x-constexpr-dfp-1.c > @@ -0,0 +1,79 @@ > +/* Test C2x constexpr. Valid code, compilation tests, DFP. */ > +/* { dg-do compile } */ > +/* { dg-options "-std=3Dc2x -pedantic-errors" } */ > + > +constexpr _Decimal32 v1 =3D __DEC32_MIN__; > +constexpr _Decimal32 v2 =3D __DEC32_SUBNORMAL_MIN__; > +constexpr _Decimal32 v3 =3D -__DEC32_MAX__; > +constexpr _Decimal64 v4 =3D __DEC32_MIN__; > +constexpr _Decimal64 v5 =3D __DEC32_SUBNORMAL_MIN__; > +constexpr _Decimal64 v6 =3D -__DEC32_MAX__; > +constexpr _Decimal64 v7 =3D __DEC64_MIN__; > +constexpr _Decimal64 v8 =3D __DEC64_SUBNORMAL_MIN__; > +constexpr _Decimal64 v9 =3D -__DEC64_MAX__; > +constexpr _Decimal128 v10 =3D __DEC32_MIN__; > +constexpr _Decimal128 v11 =3D __DEC32_SUBNORMAL_MIN__; > +constexpr _Decimal128 v12 =3D -__DEC32_MAX__; > +constexpr _Decimal128 v13 =3D __DEC64_MIN__; > +constexpr _Decimal128 v14 =3D __DEC64_SUBNORMAL_MIN__; > +constexpr _Decimal128 v15 =3D -__DEC64_MAX__; > +constexpr _Decimal128 v16 =3D __DEC128_MIN__; > +constexpr _Decimal128 v17 =3D __DEC128_SUBNORMAL_MIN__; > +constexpr _Decimal128 v18 =3D -__DEC128_MAX__; > +constexpr _Decimal32 v19 =3D 1234567L; > +constexpr _Decimal32 v20 =3D -123456700000LL; > +constexpr _Decimal64 v21 =3D 1234567890123456LL; > +constexpr _Decimal64 v22 =3D -123456789012345600LL; > +constexpr _Decimal128 v23 =3D (unsigned long long) -1; > +constexpr _Decimal32 v24 =3D 1e-101DL; > +constexpr _Decimal64 v25 =3D 1e-398DL; > +constexpr _Decimal32 v26 =3D __builtin_infd128 (); > +constexpr _Decimal128 v27 =3D __builtin_infd32 (); > +constexpr _Decimal64 v28 =3D __builtin_nand128 (""); > +constexpr _Decimal128 v29 =3D __builtin_nand32 (""); > +constexpr _Decimal32 v30 =3D __builtin_nansd32 (""); > +constexpr _Decimal64 v31 =3D __builtin_nansd64 (""); > +constexpr _Decimal128 v32 =3D __builtin_nansd128 (""); > +constexpr _Decimal32 v33 =3D {}; > +constexpr _Decimal64 v34 =3D {}; > +constexpr _Decimal128 v35 =3D {}; > + > +void > +f0 () > +{ > + (constexpr _Decimal32) { __DEC32_MIN__ }; > + (constexpr _Decimal32) { __DEC32_SUBNORMAL_MIN__ }; > + (constexpr _Decimal32) { -__DEC32_MAX__ }; > + (constexpr _Decimal64) { __DEC32_MIN__ }; > + (constexpr _Decimal64) { __DEC32_SUBNORMAL_MIN__ }; > + (constexpr _Decimal64) { -__DEC32_MAX__ }; > + (constexpr _Decimal64) { __DEC64_MIN__ }; > + (constexpr _Decimal64) { __DEC64_SUBNORMAL_MIN__ }; > + (constexpr _Decimal64) { -__DEC64_MAX__ }; > + (constexpr _Decimal128) { __DEC32_MIN__ }; > + (constexpr _Decimal128) { __DEC32_SUBNORMAL_MIN__ }; > + (constexpr _Decimal128) { -__DEC32_MAX__ }; > + (constexpr _Decimal128) { __DEC64_MIN__ }; > + (constexpr _Decimal128) { __DEC64_SUBNORMAL_MIN__ }; > + (constexpr _Decimal128) { -__DEC64_MAX__ }; > + (constexpr _Decimal128) { __DEC128_MIN__ }; > + (constexpr _Decimal128) { __DEC128_SUBNORMAL_MIN__ }; > + (constexpr _Decimal128) { -__DEC128_MAX__ }; > + (constexpr _Decimal32) { 1234567L }; > + (constexpr _Decimal32) { -123456700000LL }; > + (constexpr _Decimal64) { 1234567890123456LL }; > + (constexpr _Decimal64) { -123456789012345600LL }; > + (constexpr _Decimal128) { (unsigned long long) -1 }; > + (constexpr _Decimal32) { 1e-101DL }; > + (constexpr _Decimal64) { 1e-398DL }; > + (constexpr _Decimal32) { __builtin_infd128 () }; > + (constexpr _Decimal128) { __builtin_infd32 () }; > + (constexpr _Decimal64) { __builtin_nand128 ("") }; > + (constexpr _Decimal128) { __builtin_nand32 ("") }; > + (constexpr _Decimal32) { __builtin_nansd32 ("") }; > + (constexpr _Decimal64) { __builtin_nansd64 ("") }; > + (constexpr _Decimal128) { __builtin_nansd128 ("") }; > + (constexpr _Decimal32) {}; > + (constexpr _Decimal64) {}; > + (constexpr _Decimal128) {}; > +} > diff --git a/gcc/testsuite/gcc.dg/dfp/c2x-constexpr-dfp-2.c b/gcc/testsuit= e/gcc.dg/dfp/c2x-constexpr-dfp-2.c > new file mode 100644 > index 00000000000..8b1ecf23908 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/dfp/c2x-constexpr-dfp-2.c > @@ -0,0 +1,48 @@ > +/* Test C2x constexpr. Invalid code, compilation tests, DFP. */ > +/* { dg-do compile } */ > +/* { dg-options "-std=3Dc2x -pedantic-errors" } */ > + > +/* Test conversions between binary and decimal. */ > +constexpr _Decimal32 v1 =3D 0.0; /* { dg-error "'constexpr' initializer f= or a decimal floating-point type is of binary type" } */ > +constexpr double v2 =3D 0.0DF; /* { dg-error "'constexpr' initializer for= a binary floating-point type is of decimal type" } */ > + > +/* A conversion from signaling NaN to quiet NaN in a different format is n= ot > + valid for constexpr. */ > +constexpr _Decimal32 v3 =3D __builtin_nansd64 (""); /* { dg-error "'const= expr' initializer not representable in type of object" } */ > +constexpr _Decimal32 v4 =3D __builtin_nansd128 (""); /* { dg-error "'cons= texpr' initializer not representable in type of object" } */ > +constexpr _Decimal64 v5 =3D __builtin_nansd32 (""); /* { dg-error "'const= expr' initializer not representable in type of object" } */ > +constexpr _Decimal64 v6 =3D __builtin_nansd128 (""); /* { dg-error "'cons= texpr' initializer not representable in type of object" } */ > +constexpr _Decimal128 v7 =3D __builtin_nansd32 (""); /* { dg-error "'cons= texpr' initializer not representable in type of object" } */ > +constexpr _Decimal128 v8 =3D __builtin_nansd64 (""); /* { dg-error "'cons= texpr' initializer not representable in type of object" } */ > + > +/* Test out-of-range values, including integers. */ > +constexpr _Decimal32 v9 =3D 12345678; /* { dg-error "'constexpr' initiali= zer not representable in type of object" } */ > +constexpr _Decimal64 v10 =3D (unsigned long long) -1; /* { dg-error "'con= stexpr' initializer not representable in type of object" } */ > +constexpr _Decimal32 v11 =3D __DEC64_MIN__; /* { dg-error "'constexpr' in= itializer not representable in type of object" } */ > +constexpr _Decimal64 v12 =3D -__DEC128_MAX__; /* { dg-error "'constexpr' i= nitializer not representable in type of object" } */ > +constexpr _Decimal64 v13 =3D 12345678901234567890.DL; /* { dg-error "'con= stexpr' initializer not representable in type of object" } */ > + > +/* Test cases where the value can be represented, but the quantum exponen= t > + cannot. */ > +constexpr _Decimal32 v14 =3D 0e-200DD; /* { dg-error "'constexpr' initial= izer not representable in type of object" } */ > +constexpr _Decimal32 v15 =3D 0e200DL; /* { dg-error "'constexpr' initiali= zer not representable in type of object" } */ > + > +void > +f0 () > +{ > + (constexpr _Decimal32) { 0.0 }; /* { dg-error "'constexpr' initializer f= or a decimal floating-point type is of binary type" } */ > + (constexpr double) { 0.0DF }; /* { dg-error "'constexpr' initializer fo= r a binary floating-point type is of decimal type" } */ > + (constexpr _Decimal32) { __builtin_nansd64 ("") }; /* { dg-error "'cons= texpr' initializer not representable in type of object" } */ > + (constexpr _Decimal32) { __builtin_nansd128 ("") }; /* { dg-error "'con= stexpr' initializer not representable in type of object" } */ > + (constexpr _Decimal64) { __builtin_nansd32 ("") }; /* { dg-error "'cons= texpr' initializer not representable in type of object" } */ > + (constexpr _Decimal64) { __builtin_nansd128 ("") }; /* { dg-error "'con= stexpr' initializer not representable in type of object" } */ > + (constexpr _Decimal128) { __builtin_nansd32 ("") }; /* { dg-error "'con= stexpr' initializer not representable in type of object" } */ > + (constexpr _Decimal128) { __builtin_nansd64 ("") }; /* { dg-error "'con= stexpr' initializer not representable in type of object" } */ > + (constexpr _Decimal32) { 12345678 }; /* { dg-error "'constexpr' initial= izer not representable in type of object" } */ > + (constexpr _Decimal64) { (unsigned long long) -1 }; /* { dg-error "'con= stexpr' initializer not representable in type of object" } */ > + (constexpr _Decimal32) { __DEC64_MIN__ }; /* { dg-error "'constexpr' in= itializer not representable in type of object" } */ > + (constexpr _Decimal64) { -__DEC128_MAX__ }; /* { dg-error "'constexpr' i= nitializer not representable in type of object" } */ > + (constexpr _Decimal64) { 12345678901234567890.DL }; /* { dg-error "'con= stexpr' initializer not representable in type of object" } */ > + (constexpr _Decimal32) { 0e-200DD }; /* { dg-error "'constexpr' initial= izer not representable in type of object" } */ > + (constexpr _Decimal32) { 0e200DL }; /* { dg-error "'constexpr' initiali= zer not representable in type of object" } */ > +} > diff --git a/gcc/testsuite/gcc.dg/gnu2x-constexpr-1.c b/gcc/testsuite/gcc.= dg/gnu2x-constexpr-1.c > new file mode 100644 > index 00000000000..6078f0807e3 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/gnu2x-constexpr-1.c > @@ -0,0 +1,17 @@ > +/* Test C2x constexpr. Valid code using GNU extensions, compilation test= s. */ > +/* { dg-do compile } */ > +/* { dg-options "-std=3Dgnu2x" } */ > + > +struct s { struct { int x, y; } x; }; > +constexpr struct s v =3D { { 123, 150 } }; > +int k; > +constexpr int a[200] =3D { [v.x.x ... v.x.y] =3D 7 }; > + > +void > +f () > +{ > + switch (k) > + { > + case v.x.x ... v.x.y: ; > + } > +} > diff --git a/gcc/testsuite/gcc.target/i386/excess-precision-11.c b/gcc/tes= tsuite/gcc.target/i386/excess-precision-11.c > new file mode 100644 > index 00000000000..b83ecaec6e9 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/i386/excess-precision-11.c > @@ -0,0 +1,8 @@ > +/* Test C2x constexpr. Valid code, compilation tests, excess precision. = */ > +/* { dg-do compile } */ > +/* { dg-options "-std=3Dc2x -pedantic-errors -mfpmath=3D387 -fexcess-prec= ision=3Dstandard" } */ > + > +constexpr long double ld =3D 1.0 / 3.0; > +constexpr long double ld2 =3D 1.1; > +constexpr double d =3D (double) (1.0 / 3.0); > +constexpr double d2 =3D (double) 1.1; > diff --git a/gcc/testsuite/gcc.target/i386/excess-precision-12.c b/gcc/tes= tsuite/gcc.target/i386/excess-precision-12.c > new file mode 100644 > index 00000000000..b44f0b5bf76 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/i386/excess-precision-12.c > @@ -0,0 +1,6 @@ > +/* Test C2x constexpr. Invalid code, compilation tests, excess precision= . */ > +/* { dg-do compile } */ > +/* { dg-options "-std=3Dc2x -pedantic-errors -mfpmath=3D387 -fexcess-prec= ision=3Dstandard" } */ > + > +constexpr double d =3D 1.0 / 3.0; /* { dg-error "'constexpr' initializer n= ot representable in type of object" } */ > +constexpr double d2 =3D 1.1; /* { dg-error "'constexpr' initializer not r= epresentable in type of object" } */ >=20 > --=20 > Joseph S. Myers > joseph@codesourcery.com