diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index cc08434f5d3b..da9b619113c8 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -1780,6 +1780,8 @@ def note_uninit_fixit_remove_cond : Note< "remove the %select{'%1' if its condition|condition if it}0 " "is always %select{false|true}2">; 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< "multiple unsequenced modifications to %0">, InGroup; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index f18a6ee4b968..c89ff3866de7 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -1796,6 +1796,8 @@ public: bool TypeMayContainAuto); void ActOnUninitializedDecl(Decl *dcl, bool TypeMayContainAuto); void ActOnInitializerError(Decl *Dcl); + bool canInitializeWithParenthesizedList(QualType TargetType); + void ActOnPureSpecifier(Decl *D, SourceLocation PureSpecLoc); void ActOnCXXForRangeDecl(Decl *D); StmtResult ActOnCXXForRangeIdentifier(Scope *S, SourceLocation IdentLoc, diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 7f443b3d3ff1..fb2468f9ab93 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -9865,6 +9865,18 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, // Perform the initialization. ParenListExpr *CXXDirectInit = dyn_cast(Init); if (!VDecl->isInvalidDecl()) { + // Handle errors like: int a({0}) + if (CXXDirectInit && CXXDirectInit->getNumExprs() == 1 && + !canInitializeWithParenthesizedList(VDecl->getType())) + if (auto IList = dyn_cast(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); InitializationKind Kind = DirectInit @@ -10171,6 +10183,18 @@ void Sema::ActOnInitializerError(Decl *D) { // 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, bool TypeMayContainAuto) { // If there is no declaration, there was an error parsing it. Just ignore it. diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 634954c3e85d..a87d5efaf080 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -1221,6 +1221,17 @@ Sema::ActOnCXXTypeConstructExpr(ParsedType TypeRep, if (!TInfo) 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(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); // Avoid creating a non-type-dependent expression that contains typos. // Non-type-dependent expressions are liable to be discarded without @@ -1562,8 +1573,20 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, return ExprError(); SourceRange DirectInitRange; - if (ParenListExpr *List = dyn_cast_or_null(Initializer)) + if (ParenListExpr *List = dyn_cast_or_null(Initializer)) { DirectInitRange = List->getSourceRange(); + // Handle errors like: new int a({0}) + if (List->getNumExprs() == 1 && + !canInitializeWithParenthesizedList(AllocType)) + if (auto IList = dyn_cast(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, PlacementLParen, diff --git a/clang/test/SemaCXX/cxx0x-initializer-references.cpp b/clang/test/SemaCXX/cxx0x-initializer-references.cpp index 390047ea0752..c64511193b6e 100644 --- a/clang/test/SemaCXX/cxx0x-initializer-references.cpp +++ b/clang/test/SemaCXX/cxx0x-initializer-references.cpp @@ -72,10 +72,9 @@ namespace reference { } void edge_cases() { - // FIXME: very poor error message - int const &b({0}); // expected-error {{could not bind}} + int const &b({0}); // expected-error {{list-initializer for non-class type 'const int &' must not be parenthesized}} + const int (&arr)[3] ({1, 2, 3}); // expected-error {{list-initializer for non-class type 'const int (&)[3]' must not be parenthesized}} } - } namespace PR12182 { diff --git a/clang/test/SemaCXX/cxx0x-initializer-scalars.cpp b/clang/test/SemaCXX/cxx0x-initializer-scalars.cpp index c9d5ffd19429..65b57a5584ab 100644 --- a/clang/test/SemaCXX/cxx0x-initializer-scalars.cpp +++ b/clang/test/SemaCXX/cxx0x-initializer-scalars.cpp @@ -91,10 +91,23 @@ namespace integral { } void edge_cases() { - // FIXME: very poor error message - int a({0}); // expected-error {{cannot initialize}} - (void) int({0}); // expected-error {{functional-style cast}} - new int({0}); // expected-error {{cannot initialize}} + int a({0}); // expected-error {{list-initializer for non-class type 'int' must not be parenthesized}} + (void) int({0}); // expected-error {{list-initializer for non-class type 'int' must not be parenthesized}} + new int({0}); // expected-error {{list-initializer for non-class type 'int' must not be parenthesized}} + + 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 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 = {}) {