aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSerge Pavlov <sepavloff@gmail.com>2016-11-12 15:38:55 +0000
committerSerge Pavlov <sepavloff@gmail.com>2016-11-12 15:38:55 +0000
commit3852637005b1528aac2d2e12ac7c03cb6f300e26 (patch)
treef4b28d3d5541f27d3f6ab31547ed5315a85a0749
parenta583be4e52d9f7d0fd36e1d44836d8297cedda2a (diff)
downloadllvm-3852637005b1528aac2d2e12ac7c03cb6f300e26.zip
llvm-3852637005b1528aac2d2e12ac7c03cb6f300e26.tar.gz
llvm-3852637005b1528aac2d2e12ac7c03cb6f300e26.tar.bz2
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
-rw-r--r--clang/include/clang/Basic/DiagnosticSemaKinds.td2
-rw-r--r--clang/include/clang/Sema/Sema.h2
-rw-r--r--clang/lib/Sema/SemaDecl.cpp24
-rw-r--r--clang/lib/Sema/SemaExprCXX.cpp25
-rw-r--r--clang/test/SemaCXX/cxx0x-initializer-references.cpp5
-rw-r--r--clang/test/SemaCXX/cxx0x-initializer-scalars.cpp21
6 files changed, 71 insertions, 8 deletions
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index cc08434..da9b619 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<Unsequenced>;
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index f18a6ee..c89ff386 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 7f443b3..fb2468f 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<ParenListExpr>(Init);
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);
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 634954c..a87d5ef 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<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);
// 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<ParenListExpr>(Initializer))
+ if (ParenListExpr *List = dyn_cast_or_null<ParenListExpr>(Initializer)) {
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,
PlacementLParen,
diff --git a/clang/test/SemaCXX/cxx0x-initializer-references.cpp b/clang/test/SemaCXX/cxx0x-initializer-references.cpp
index 390047e..c6451119 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 c9d5ffd..65b57a55 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<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 = {}) {