forked from OSchip/llvm-project
[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
This commit is contained in:
parent
e001a4e489
commit
3d2ab237f1
|
@ -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
|
||||
-------------------------------------------------
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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>();
|
||||
|
|
|
@ -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}}
|
||||
};
|
||||
|
|
|
@ -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}}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue