Author: Timm Bäder Date: 2022-08-19T08:06:12+02:00 New Revision: 3d2ab237f157908d595581cfbeeb0a9ff33bb249
URL: https://github.com/llvm/llvm-project/commit/3d2ab237f157908d595581cfbeeb0a9ff33bb249 DIFF: https://github.com/llvm/llvm-project/commit/3d2ab237f157908d595581cfbeeb0a9ff33bb249.diff LOG: [clang] Improve diagnostics for uninitialized constexpr variables Instead of complaining about default initialization, tell users that constexpr variables need to be initialized by a constant expression. Differential Revision: https://reviews.llvm.org/D131662 Added: Modified: clang/docs/ReleaseNotes.rst clang/lib/Sema/SemaDecl.cpp clang/lib/Sema/SemaInit.cpp clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp clang/test/SemaCXX/constant-expression-cxx11.cpp Removed: ################################################################################ diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 5b0f795606137..ccbe7a510ea80 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -101,6 +101,8 @@ Improvements to Clang's diagnostics - Clang will now print more information about failed static assertions. In particular, simple static assertion expressions are evaluated to their compile-time value and printed out if the assertion fails. +- Diagnostics about uninitialized ``constexpr`` varaibles have been improved + to mention the missing constant initializer. Non-comprehensive list of changes in this release ------------------------------------------------- diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 7e7433d13d002..d4c8377bbce7f 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -13372,8 +13372,12 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) { // Provide a specific diagnostic for uninitialized variable // definitions with incomplete array type. if (Type->isIncompleteArrayType()) { - Diag(Var->getLocation(), - diag::err_typecheck_incomplete_array_needs_initializer); + if (Var->isConstexpr()) + Diag(Var->getLocation(), diag::err_constexpr_var_requires_const_init) + << Var; + else + Diag(Var->getLocation(), + diag::err_typecheck_incomplete_array_needs_initializer); Var->setInvalidDecl(); return; } diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index d9996e6ddf6a4..b5cf96af07afa 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -8053,19 +8053,29 @@ ExprResult InitializationSequence::Perform(Sema &S, return ExprError(); } if (!ZeroInitializationFixit.empty()) { - unsigned DiagID = diag::err_default_init_const; - if (Decl *D = Entity.getDecl()) - if (S.getLangOpts().MSVCCompat && D->hasAttr<SelectAnyAttr>()) - DiagID = diag::ext_default_init_const; + const Decl *D = Entity.getDecl(); + const auto *VD = dyn_cast_or_null<VarDecl>(D); + QualType DestType = Entity.getType(); // The initialization would have succeeded with this fixit. Since the fixit // is on the error, we need to build a valid AST in this case, so this isn't // handled in the Failed() branch above. - QualType DestType = Entity.getType(); - S.Diag(Kind.getLocation(), DiagID) - << DestType << (bool)DestType->getAs<RecordType>() - << FixItHint::CreateInsertion(ZeroInitializationFixitLoc, - ZeroInitializationFixit); + if (!DestType->isRecordType() && VD && VD->isConstexpr()) { + // Use a more useful diagnostic for constexpr variables. + S.Diag(Kind.getLocation(), diag::err_constexpr_var_requires_const_init) + << VD + << FixItHint::CreateInsertion(ZeroInitializationFixitLoc, + ZeroInitializationFixit); + } else { + unsigned DiagID = diag::err_default_init_const; + if (S.getLangOpts().MSVCCompat && D && D->hasAttr<SelectAnyAttr>()) + DiagID = diag::ext_default_init_const; + + S.Diag(Kind.getLocation(), DiagID) + << DestType << (bool)DestType->getAs<RecordType>() + << FixItHint::CreateInsertion(ZeroInitializationFixitLoc, + ZeroInitializationFixit); + } } if (getKind() == DependentSequence) { @@ -9464,6 +9474,10 @@ bool InitializationSequence::Diagnose(Sema &S, << Entity.getName(); S.Diag(Entity.getDecl()->getLocation(), diag::note_previous_decl) << Entity.getName(); + } else if (const auto *VD = dyn_cast_if_present<VarDecl>(Entity.getDecl()); + VD && VD->isConstexpr()) { + S.Diag(Kind.getLocation(), diag::err_constexpr_var_requires_const_init) + << VD; } else { S.Diag(Kind.getLocation(), diag::err_default_init_const) << DestType << (bool)DestType->getAs<RecordType>(); diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp index 59e3dcf6ed657..a28a5f91c4775 100644 --- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp +++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp @@ -37,7 +37,7 @@ struct s2 { #if __cplusplus <= 201402L && !defined(MS_ABI) // expected-error@-2 {{requires an initializer}} #else - // expected-error@-4 {{default initialization of an object of const}} + // expected-error@-4 {{constexpr variable 'mi2' must be initialized by a constant expression}} #endif mutable constexpr int mi3 = 3; // expected-error-re {{non-static data member cannot be constexpr{{$}}}} expected-error {{'mutable' and 'const' cannot be mixed}} }; diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp index 3720b277af7a9..b1d80e3c428d3 100644 --- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp +++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp @@ -18,7 +18,7 @@ extern int (*const d)(int); // A variable declaration which uses the constexpr specifier shall have an // initializer and shall be initialized by a constant expression. -constexpr int ni1; // expected-error {{default initialization of an object of const type 'const int'}} +constexpr int ni1; // expected-error {{constexpr variable 'ni1' must be initialized by a constant expression}} constexpr struct C { C(); } ni2; // expected-error {{cannot have non-literal type 'const struct C'}} expected-note 3{{has no constexpr constructors}} constexpr double &ni3; // expected-error {{declaration of reference variable 'ni3' requires an initializer}} diff --git a/clang/test/SemaCXX/constant-expression-cxx11.cpp b/clang/test/SemaCXX/constant-expression-cxx11.cpp index 4b856d319c3d5..8d8c9488576c1 100644 --- a/clang/test/SemaCXX/constant-expression-cxx11.cpp +++ b/clang/test/SemaCXX/constant-expression-cxx11.cpp @@ -27,6 +27,10 @@ struct MemberZero { constexpr int zero() const { return 0; } }; +constexpr int arr[]; // expected-error {{constexpr variable 'arr' must be initialized by a constant expression}} +constexpr int arr2[2]; // expected-error {{constexpr variable 'arr2' must be initialized by a constant expression}} +constexpr int arr3[2] = {}; + namespace DerivedToVBaseCast { struct U { int n; }; @@ -1298,7 +1302,7 @@ namespace ExternConstexpr { void f() { extern constexpr int i; // expected-error {{constexpr variable declaration must be a definition}} constexpr int j = 0; - constexpr int k; // expected-error {{default initialization of an object of const type}} + constexpr int k; // expected-error {{constexpr variable 'k' must be initialized by a constant expression}} } extern const int q; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits