[clang] 3d2ab23 - [clang] Improve diagnostics for uninitialized constexpr variables
Timm Bäder via cfe-commits
cfe-commits at lists.llvm.org
Thu Aug 18 23:06:50 PDT 2022
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 at -2 {{requires an initializer}}
#else
- // expected-error at -4 {{default initialization of an object of const}}
+ // expected-error at -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;
More information about the cfe-commits
mailing list