forked from OSchip/llvm-project
Use descriptive message if list initializer is incorrectly parenthesized.
If initializer contains parentheses around braced list where it is not allowed, as in construct int({0}), clang issued message like `functional-style cast from 'void' to 'int' is not allowed`, which does not help much. Both gcc and msvc issue message `list-initializer for non-class type must not be parenthesized`, which is more descriptive. This change implements similar message for clang. Differential Revision: https://reviews.llvm.org/D25816 llvm-svn: 286721
This commit is contained in:
parent
a583be4e52
commit
3852637005
|
@ -1780,6 +1780,8 @@ def note_uninit_fixit_remove_cond : Note<
|
||||||
"remove the %select{'%1' if its condition|condition if it}0 "
|
"remove the %select{'%1' if its condition|condition if it}0 "
|
||||||
"is always %select{false|true}2">;
|
"is always %select{false|true}2">;
|
||||||
def err_init_incomplete_type : Error<"initialization of incomplete type %0">;
|
def err_init_incomplete_type : Error<"initialization of incomplete type %0">;
|
||||||
|
def err_list_init_in_parens : Error<"list-initializer for non-class type %0 "
|
||||||
|
"must not be parenthesized">;
|
||||||
|
|
||||||
def warn_unsequenced_mod_mod : Warning<
|
def warn_unsequenced_mod_mod : Warning<
|
||||||
"multiple unsequenced modifications to %0">, InGroup<Unsequenced>;
|
"multiple unsequenced modifications to %0">, InGroup<Unsequenced>;
|
||||||
|
|
|
@ -1796,6 +1796,8 @@ public:
|
||||||
bool TypeMayContainAuto);
|
bool TypeMayContainAuto);
|
||||||
void ActOnUninitializedDecl(Decl *dcl, bool TypeMayContainAuto);
|
void ActOnUninitializedDecl(Decl *dcl, bool TypeMayContainAuto);
|
||||||
void ActOnInitializerError(Decl *Dcl);
|
void ActOnInitializerError(Decl *Dcl);
|
||||||
|
bool canInitializeWithParenthesizedList(QualType TargetType);
|
||||||
|
|
||||||
void ActOnPureSpecifier(Decl *D, SourceLocation PureSpecLoc);
|
void ActOnPureSpecifier(Decl *D, SourceLocation PureSpecLoc);
|
||||||
void ActOnCXXForRangeDecl(Decl *D);
|
void ActOnCXXForRangeDecl(Decl *D);
|
||||||
StmtResult ActOnCXXForRangeIdentifier(Scope *S, SourceLocation IdentLoc,
|
StmtResult ActOnCXXForRangeIdentifier(Scope *S, SourceLocation IdentLoc,
|
||||||
|
|
|
@ -9865,6 +9865,18 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
|
||||||
// Perform the initialization.
|
// Perform the initialization.
|
||||||
ParenListExpr *CXXDirectInit = dyn_cast<ParenListExpr>(Init);
|
ParenListExpr *CXXDirectInit = dyn_cast<ParenListExpr>(Init);
|
||||||
if (!VDecl->isInvalidDecl()) {
|
if (!VDecl->isInvalidDecl()) {
|
||||||
|
// Handle errors like: int a({0})
|
||||||
|
if (CXXDirectInit && CXXDirectInit->getNumExprs() == 1 &&
|
||||||
|
!canInitializeWithParenthesizedList(VDecl->getType()))
|
||||||
|
if (auto IList = dyn_cast<InitListExpr>(CXXDirectInit->getExpr(0))) {
|
||||||
|
Diag(VDecl->getLocation(), diag::err_list_init_in_parens)
|
||||||
|
<< VDecl->getType() << CXXDirectInit->getSourceRange()
|
||||||
|
<< FixItHint::CreateRemoval(CXXDirectInit->getLocStart())
|
||||||
|
<< FixItHint::CreateRemoval(CXXDirectInit->getLocEnd());
|
||||||
|
Init = IList;
|
||||||
|
CXXDirectInit = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
InitializedEntity Entity = InitializedEntity::InitializeVariable(VDecl);
|
InitializedEntity Entity = InitializedEntity::InitializeVariable(VDecl);
|
||||||
InitializationKind Kind =
|
InitializationKind Kind =
|
||||||
DirectInit
|
DirectInit
|
||||||
|
@ -10171,6 +10183,18 @@ void Sema::ActOnInitializerError(Decl *D) {
|
||||||
// though.
|
// though.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Checks if an object of the given type can be initialized with parenthesized
|
||||||
|
/// init-list.
|
||||||
|
///
|
||||||
|
/// \param TargetType Type of object being initialized.
|
||||||
|
///
|
||||||
|
/// The function is used to detect wrong initializations, such as 'int({0})'.
|
||||||
|
///
|
||||||
|
bool Sema::canInitializeWithParenthesizedList(QualType TargetType) {
|
||||||
|
return TargetType->isDependentType() || TargetType->isRecordType() ||
|
||||||
|
TargetType->getContainedAutoType();
|
||||||
|
}
|
||||||
|
|
||||||
void Sema::ActOnUninitializedDecl(Decl *RealDecl,
|
void Sema::ActOnUninitializedDecl(Decl *RealDecl,
|
||||||
bool TypeMayContainAuto) {
|
bool TypeMayContainAuto) {
|
||||||
// If there is no declaration, there was an error parsing it. Just ignore it.
|
// If there is no declaration, there was an error parsing it. Just ignore it.
|
||||||
|
|
|
@ -1221,6 +1221,17 @@ Sema::ActOnCXXTypeConstructExpr(ParsedType TypeRep,
|
||||||
if (!TInfo)
|
if (!TInfo)
|
||||||
TInfo = Context.getTrivialTypeSourceInfo(Ty, SourceLocation());
|
TInfo = Context.getTrivialTypeSourceInfo(Ty, SourceLocation());
|
||||||
|
|
||||||
|
// Handle errors like: int({0})
|
||||||
|
if (exprs.size() == 1 && !canInitializeWithParenthesizedList(Ty) &&
|
||||||
|
LParenLoc.isValid() && RParenLoc.isValid())
|
||||||
|
if (auto IList = dyn_cast<InitListExpr>(exprs[0])) {
|
||||||
|
Diag(TInfo->getTypeLoc().getLocStart(), diag::err_list_init_in_parens)
|
||||||
|
<< Ty << IList->getSourceRange()
|
||||||
|
<< FixItHint::CreateRemoval(LParenLoc)
|
||||||
|
<< FixItHint::CreateRemoval(RParenLoc);
|
||||||
|
LParenLoc = RParenLoc = SourceLocation();
|
||||||
|
}
|
||||||
|
|
||||||
auto Result = BuildCXXTypeConstructExpr(TInfo, LParenLoc, exprs, RParenLoc);
|
auto Result = BuildCXXTypeConstructExpr(TInfo, LParenLoc, exprs, RParenLoc);
|
||||||
// Avoid creating a non-type-dependent expression that contains typos.
|
// Avoid creating a non-type-dependent expression that contains typos.
|
||||||
// Non-type-dependent expressions are liable to be discarded without
|
// Non-type-dependent expressions are liable to be discarded without
|
||||||
|
@ -1562,8 +1573,20 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
|
||||||
return ExprError();
|
return ExprError();
|
||||||
|
|
||||||
SourceRange DirectInitRange;
|
SourceRange DirectInitRange;
|
||||||
if (ParenListExpr *List = dyn_cast_or_null<ParenListExpr>(Initializer))
|
if (ParenListExpr *List = dyn_cast_or_null<ParenListExpr>(Initializer)) {
|
||||||
DirectInitRange = List->getSourceRange();
|
DirectInitRange = List->getSourceRange();
|
||||||
|
// Handle errors like: new int a({0})
|
||||||
|
if (List->getNumExprs() == 1 &&
|
||||||
|
!canInitializeWithParenthesizedList(AllocType))
|
||||||
|
if (auto IList = dyn_cast<InitListExpr>(List->getExpr(0))) {
|
||||||
|
Diag(TInfo->getTypeLoc().getLocStart(), diag::err_list_init_in_parens)
|
||||||
|
<< AllocType << List->getSourceRange()
|
||||||
|
<< FixItHint::CreateRemoval(List->getLocStart())
|
||||||
|
<< FixItHint::CreateRemoval(List->getLocEnd());
|
||||||
|
DirectInitRange = SourceRange();
|
||||||
|
Initializer = IList;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return BuildCXXNew(SourceRange(StartLoc, D.getLocEnd()), UseGlobal,
|
return BuildCXXNew(SourceRange(StartLoc, D.getLocEnd()), UseGlobal,
|
||||||
PlacementLParen,
|
PlacementLParen,
|
||||||
|
|
|
@ -72,10 +72,9 @@ namespace reference {
|
||||||
}
|
}
|
||||||
|
|
||||||
void edge_cases() {
|
void edge_cases() {
|
||||||
// FIXME: very poor error message
|
int const &b({0}); // expected-error {{list-initializer for non-class type 'const int &' must not be parenthesized}}
|
||||||
int const &b({0}); // expected-error {{could not bind}}
|
const int (&arr)[3] ({1, 2, 3}); // expected-error {{list-initializer for non-class type 'const int (&)[3]' must not be parenthesized}}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace PR12182 {
|
namespace PR12182 {
|
||||||
|
|
|
@ -91,10 +91,23 @@ namespace integral {
|
||||||
}
|
}
|
||||||
|
|
||||||
void edge_cases() {
|
void edge_cases() {
|
||||||
// FIXME: very poor error message
|
int a({0}); // expected-error {{list-initializer for non-class type 'int' must not be parenthesized}}
|
||||||
int a({0}); // expected-error {{cannot initialize}}
|
(void) int({0}); // expected-error {{list-initializer for non-class type 'int' must not be parenthesized}}
|
||||||
(void) int({0}); // expected-error {{functional-style cast}}
|
new int({0}); // expected-error {{list-initializer for non-class type 'int' must not be parenthesized}}
|
||||||
new int({0}); // expected-error {{cannot initialize}}
|
|
||||||
|
int *b({0}); // expected-error {{list-initializer for non-class type 'int *' must not be parenthesized}}
|
||||||
|
typedef int *intptr;
|
||||||
|
int *c = intptr({0}); // expected-error {{list-initializer for non-class type 'intptr' (aka 'int *') must not be parenthesized}}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T> void dependent_edge_cases() {
|
||||||
|
T a({0});
|
||||||
|
(void) T({0});
|
||||||
|
new T({0});
|
||||||
|
|
||||||
|
T *b({0});
|
||||||
|
typedef T *tptr;
|
||||||
|
T *c = tptr({0});
|
||||||
}
|
}
|
||||||
|
|
||||||
void default_argument(int i = {}) {
|
void default_argument(int i = {}) {
|
||||||
|
|
Loading…
Reference in New Issue