r298676 - Fix handling of initialization from parenthesized initializer list.
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Thu Mar 23 18:14:26 PDT 2017
Author: rsmith
Date: Thu Mar 23 20:14:25 2017
New Revision: 298676
URL: http://llvm.org/viewvc/llvm-project?rev=298676&view=rev
Log:
Fix handling of initialization from parenthesized initializer list.
This change fixes a crash on initialization of a reference from ({}) during
template instantiation and incidentally improves diagnostics.
This reverts a prior attempt to handle this in r286721. Instead, we teach the
initialization code that initialization cannot be performed if a source type
is required and the initializer is an initializer list (which is not an
expression and does not have a type), and likewise for function-style cast
expressions.
Modified:
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/include/clang/Sema/Initialization.h
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaExprCXX.cpp
cfe/trunk/lib/Sema/SemaInit.cpp
cfe/trunk/test/SemaCXX/cxx0x-initializer-constructor.cpp
cfe/trunk/test/SemaCXX/cxx0x-initializer-references.cpp
cfe/trunk/test/SemaCXX/cxx0x-initializer-scalars.cpp
cfe/trunk/test/SemaCXX/type-convert-construct.cpp
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=298676&r1=298675&r2=298676&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Mar 23 20:14:25 2017
@@ -1814,8 +1814,9 @@ 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 err_list_init_in_parens : Error<
+ "cannot initialize %select{non-class|reference}0 type %1 with a "
+ "parenthesized initializer list">;
def warn_unsequenced_mod_mod : Warning<
"multiple unsequenced modifications to %0">, InGroup<Unsequenced>;
@@ -5865,8 +5866,8 @@ def err_builtin_func_cast_more_than_one_
"function-style cast to a builtin type can only take one argument">;
def err_value_init_for_array_type : Error<
"array types cannot be value-initialized">;
-def err_value_init_for_function_type : Error<
- "function types cannot be value-initialized">;
+def err_init_for_function_type : Error<
+ "cannot create object of function type %0">;
def warn_format_nonliteral_noargs : Warning<
"format string is not a string literal (potentially insecure)">,
InGroup<FormatSecurity>;
Modified: cfe/trunk/include/clang/Sema/Initialization.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Initialization.h?rev=298676&r1=298675&r2=298676&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Initialization.h (original)
+++ cfe/trunk/include/clang/Sema/Initialization.h Thu Mar 23 20:14:25 2017
@@ -822,6 +822,8 @@ public:
enum FailureKind {
/// \brief Too many initializers provided for a reference.
FK_TooManyInitsForReference,
+ /// \brief Reference initialized from a parenthesized initializer list.
+ FK_ParenthesizedListInitForReference,
/// \brief Array must be initialized with an initializer list.
FK_ArrayNeedsInitList,
/// \brief Array must be initialized with an initializer list or a
@@ -866,6 +868,8 @@ public:
FK_ConversionFromPropertyFailed,
/// \brief Too many initializers for scalar
FK_TooManyInitsForScalar,
+ /// \brief Scalar initialized from a parenthesized initializer list.
+ FK_ParenthesizedListInitForScalar,
/// \brief Reference initialization from an initializer list
FK_ReferenceBindingToInitList,
/// \brief Initialization of some unused destination type with an
@@ -892,7 +896,7 @@ public:
/// having its address taken.
FK_AddressOfUnaddressableFunction,
/// \brief List-copy-initialization chose an explicit constructor.
- FK_ExplicitConstructor
+ FK_ExplicitConstructor,
};
private:
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=298676&r1=298675&r2=298676&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Thu Mar 23 20:14:25 2017
@@ -1822,7 +1822,6 @@ public:
void AddInitializerToDecl(Decl *dcl, Expr *init, bool DirectInit);
void ActOnUninitializedDecl(Decl *dcl);
void ActOnInitializerError(Decl *Dcl);
- bool canInitializeWithParenthesizedList(QualType TargetType);
void ActOnPureSpecifier(Decl *D, SourceLocation PureSpecLoc);
void ActOnCXXForRangeDecl(Decl *D);
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=298676&r1=298675&r2=298676&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Thu Mar 23 20:14:25 2017
@@ -10102,18 +10102,6 @@ void Sema::AddInitializerToDecl(Decl *Re
// 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 = InitializationKind::CreateForInit(
VDecl->getLocation(), DirectInit, Init);
@@ -10413,18 +10401,6 @@ 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) {
// If there is no declaration, there was an error parsing it. Just ignore it.
if (!RealDecl)
Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=298676&r1=298675&r2=298676&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Thu Mar 23 20:14:25 2017
@@ -1228,17 +1228,6 @@ Sema::ActOnCXXTypeConstructExpr(ParsedTy
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
@@ -1295,46 +1284,51 @@ Sema::BuildCXXTypeConstructExpr(TypeSour
}
// C++ [expr.type.conv]p1:
- // If the expression list is a single expression, the type conversion
- // expression is equivalent (in definedness, and if defined in meaning) to the
- // corresponding cast expression.
- if (Exprs.size() == 1 && !ListInitialization) {
+ // If the expression list is a parenthesized single expression, the type
+ // conversion expression is equivalent (in definedness, and if defined in
+ // meaning) to the corresponding cast expression.
+ if (Exprs.size() == 1 && !ListInitialization &&
+ !isa<InitListExpr>(Exprs[0])) {
Expr *Arg = Exprs[0];
return BuildCXXFunctionalCastExpr(TInfo, Ty, LParenLoc, Arg, RParenLoc);
}
- // C++14 [expr.type.conv]p2: The expression T(), where T is a
- // simple-type-specifier or typename-specifier for a non-array complete
- // object type or the (possibly cv-qualified) void type, creates a prvalue
- // of the specified type, whose value is that produced by value-initializing
- // an object of type T.
+ // For an expression of the form T(), T shall not be an array type.
QualType ElemTy = Ty;
if (Ty->isArrayType()) {
if (!ListInitialization)
- return ExprError(Diag(TyBeginLoc,
- diag::err_value_init_for_array_type) << FullRange);
+ return ExprError(Diag(TyBeginLoc, diag::err_value_init_for_array_type)
+ << FullRange);
ElemTy = Context.getBaseElementType(Ty);
}
- if (!ListInitialization && Ty->isFunctionType())
- return ExprError(Diag(TyBeginLoc, diag::err_value_init_for_function_type)
- << FullRange);
-
+ // There doesn't seem to be an explicit rule against this but sanity demands
+ // we only construct objects with object types.
+ if (Ty->isFunctionType())
+ return ExprError(Diag(TyBeginLoc, diag::err_init_for_function_type)
+ << Ty << FullRange);
+
+ // C++17 [expr.type.conv]p2:
+ // If the type is cv void and the initializer is (), the expression is a
+ // prvalue of the specified type that performs no initialization.
if (!Ty->isVoidType() &&
RequireCompleteType(TyBeginLoc, ElemTy,
diag::err_invalid_incomplete_type_use, FullRange))
return ExprError();
+ // Otherwise, the expression is a prvalue of the specified type whose
+ // result object is direct-initialized (11.6) with the initializer.
InitializationSequence InitSeq(*this, Entity, Kind, Exprs);
ExprResult Result = InitSeq.Perform(*this, Entity, Kind, Exprs);
- if (Result.isInvalid() || !ListInitialization)
+ if (Result.isInvalid())
return Result;
Expr *Inner = Result.get();
if (CXXBindTemporaryExpr *BTE = dyn_cast_or_null<CXXBindTemporaryExpr>(Inner))
Inner = BTE->getSubExpr();
- if (!isa<CXXTemporaryObjectExpr>(Inner)) {
+ if (!isa<CXXTemporaryObjectExpr>(Inner) &&
+ !isa<CXXScalarValueInitExpr>(Inner)) {
// If we created a CXXTemporaryObjectExpr, that node also represents the
// functional cast. Otherwise, create an explicit cast to represent
// the syntactic form of a functional-style cast that was used here.
@@ -1590,20 +1584,8 @@ Sema::ActOnCXXNew(SourceLocation StartLo
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,
Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=298676&r1=298675&r2=298676&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Thu Mar 23 20:14:25 2017
@@ -3112,6 +3112,7 @@ bool InitializationSequence::isAmbiguous
switch (getFailureKind()) {
case FK_TooManyInitsForReference:
+ case FK_ParenthesizedListInitForReference:
case FK_ArrayNeedsInitList:
case FK_ArrayNeedsInitListOrStringLiteral:
case FK_ArrayNeedsInitListOrWideStringLiteral:
@@ -3129,6 +3130,7 @@ bool InitializationSequence::isAmbiguous
case FK_ConversionFailed:
case FK_ConversionFromPropertyFailed:
case FK_TooManyInitsForScalar:
+ case FK_ParenthesizedListInitForScalar:
case FK_ReferenceBindingToInitList:
case FK_InitListBadDestinationType:
case FK_DefaultInitOfConst:
@@ -5179,6 +5181,12 @@ void InitializationSequence::InitializeF
// (Therefore, multiple arguments are not permitted.)
if (Args.size() != 1)
SetFailed(FK_TooManyInitsForReference);
+ // C++17 [dcl.init.ref]p5:
+ // A reference [...] is initialized by an expression [...] as follows:
+ // If the initializer is not an expression, presumably we should reject,
+ // but the standard fails to actually say so.
+ else if (isa<InitListExpr>(Args[0]))
+ SetFailed(FK_ParenthesizedListInitForReference);
else
TryReferenceInitialization(S, Entity, Kind, Args[0], *this);
return;
@@ -5344,11 +5352,16 @@ void InitializationSequence::InitializeF
return;
}
+ assert(Args.size() >= 1 && "Zero-argument case handled above");
+
+ // The remaining cases all need a source type.
if (Args.size() > 1) {
SetFailed(FK_TooManyInitsForScalar);
return;
+ } else if (isa<InitListExpr>(Args[0])) {
+ SetFailed(FK_ParenthesizedListInitForScalar);
+ return;
}
- assert(Args.size() == 1 && "Zero-argument case handled above");
// - Otherwise, if the source type is a (possibly cv-qualified) class
// type, conversion functions are considered.
@@ -7389,6 +7402,10 @@ bool InitializationSequence::Diagnose(Se
S.Diag(Kind.getLocation(), diag::err_reference_has_multiple_inits)
<< SourceRange(Args.front()->getLocStart(), Args.back()->getLocEnd());
break;
+ case FK_ParenthesizedListInitForReference:
+ S.Diag(Kind.getLocation(), diag::err_list_init_in_parens)
+ << 1 << Entity.getType() << Args[0]->getSourceRange();
+ break;
case FK_ArrayNeedsInitList:
S.Diag(Kind.getLocation(), diag::err_array_init_not_init_list) << 0;
@@ -7600,6 +7617,11 @@ bool InitializationSequence::Diagnose(Se
break;
}
+ case FK_ParenthesizedListInitForScalar:
+ S.Diag(Kind.getLocation(), diag::err_list_init_in_parens)
+ << 0 << Entity.getType() << Args[0]->getSourceRange();
+ break;
+
case FK_ReferenceBindingToInitList:
S.Diag(Kind.getLocation(), diag::err_reference_bind_init_list)
<< DestType.getNonReferenceType() << Args[0]->getSourceRange();
@@ -7782,6 +7804,10 @@ void InitializationSequence::dump(raw_os
OS << "too many initializers for reference";
break;
+ case FK_ParenthesizedListInitForReference:
+ OS << "parenthesized list init for reference";
+ break;
+
case FK_ArrayNeedsInitList:
OS << "array requires initializer list";
break;
@@ -7866,6 +7892,10 @@ void InitializationSequence::dump(raw_os
OS << "too many initializers for scalar";
break;
+ case FK_ParenthesizedListInitForScalar:
+ OS << "parenthesized list init for reference";
+ break;
+
case FK_ReferenceBindingToInitList:
OS << "referencing binding to initializer list";
break;
Modified: cfe/trunk/test/SemaCXX/cxx0x-initializer-constructor.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx0x-initializer-constructor.cpp?rev=298676&r1=298675&r2=298676&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx0x-initializer-constructor.cpp (original)
+++ cfe/trunk/test/SemaCXX/cxx0x-initializer-constructor.cpp Thu Mar 23 20:14:25 2017
@@ -173,8 +173,7 @@ namespace objects {
// invalid
H h1({1, 2}); // expected-error {{no matching constructor}}
(void) new H({1, 2}); // expected-error {{no matching constructor}}
- // FIXME: Bad diagnostic, mentions void type instead of init list.
- (void) H({1, 2}); // expected-error {{no matching conversion}}
+ (void) H({1, 2}); // expected-error {{no matching constructor}}
// valid (by copy constructor).
H h2({1, nullptr});
Modified: cfe/trunk/test/SemaCXX/cxx0x-initializer-references.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx0x-initializer-references.cpp?rev=298676&r1=298675&r2=298676&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx0x-initializer-references.cpp (original)
+++ cfe/trunk/test/SemaCXX/cxx0x-initializer-references.cpp Thu Mar 23 20:14:25 2017
@@ -71,10 +71,22 @@ namespace reference {
static_assert(sizeof(h({1, 2})) == sizeof(two), "bad overload resolution");
}
+ struct X {};
+
void edge_cases() {
- 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}}
+ int const &b({0}); // expected-error {{cannot initialize reference type 'const int &' with a parenthesized initializer list}}
+ const int (&arr)[3] ({1, 2, 3}); // expected-error {{cannot initialize reference type 'const int (&)[3]' with a parenthesized initializer list}}
+ const X &x({}); // expected-error {{cannot initialize reference type 'const reference::X &' with a parenthesized initializer list}}
+ }
+
+ template<typename T> void dependent_edge_cases() {
+ T b({}); // expected-error-re 3{{cannot initialize reference type {{.*}} with a parenthesized init}}
+ T({}); // expected-error-re 3{{cannot initialize reference type {{.*}} with a parenthesized init}}
}
+ template void dependent_edge_cases<X>(); // ok
+ template void dependent_edge_cases<const int&>(); // expected-note {{instantiation of}}
+ template void dependent_edge_cases<const int(&)[1]>(); // expected-note {{instantiation of}}
+ template void dependent_edge_cases<const X&>(); // expected-note {{instantiation of}}
}
namespace PR12182 {
Modified: cfe/trunk/test/SemaCXX/cxx0x-initializer-scalars.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx0x-initializer-scalars.cpp?rev=298676&r1=298675&r2=298676&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx0x-initializer-scalars.cpp (original)
+++ cfe/trunk/test/SemaCXX/cxx0x-initializer-scalars.cpp Thu Mar 23 20:14:25 2017
@@ -91,13 +91,13 @@ namespace integral {
}
void edge_cases() {
- 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 a({0}); // expected-error {{cannot initialize non-class type 'int' with a parenthesized initializer list}}
+ (void) int({0}); // expected-error {{cannot initialize non-class type 'int' with a parenthesized initializer list}}
+ new int({0}); // expected-error {{cannot initialize non-class type 'int' with a parenthesized initializer list}}
- int *b({0}); // expected-error {{list-initializer for non-class type 'int *' must not be parenthesized}}
+ int *b({0}); // expected-error {{cannot initialize non-class type 'int *' with a parenthesized initializer list}}
typedef int *intptr;
- int *c = intptr({0}); // expected-error {{list-initializer for non-class type 'intptr' (aka 'int *') must not be parenthesized}}
+ int *c = intptr({0}); // expected-error {{cannot initialize non-class type 'intptr' (aka 'int *') with a parenthesized initializer list}}
}
template<typename T> void dependent_edge_cases() {
Modified: cfe/trunk/test/SemaCXX/type-convert-construct.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/type-convert-construct.cpp?rev=298676&r1=298675&r2=298676&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/type-convert-construct.cpp (original)
+++ cfe/trunk/test/SemaCXX/type-convert-construct.cpp Thu Mar 23 20:14:25 2017
@@ -8,7 +8,15 @@ void f() {
typedef int arr[];
int v3 = arr(); // expected-error {{array types cannot be value-initialized}}
typedef void fn_ty();
- fn_ty(); // expected-error {{function types cannot be value-initialized}}
+ fn_ty(); // expected-error {{cannot create object of function type 'fn_ty'}}
+ fn_ty(0); // expected-error {{functional-style cast from 'int' to 'fn_ty'}}
+ fn_ty(0, 0); // expected-error {{cannot create object of function type 'fn_ty'}}
+#if __cplusplus >= 201103L
+ fn_ty{}; // expected-error {{cannot create object of function type 'fn_ty'}}
+ fn_ty{0}; // expected-error {{cannot create object of function type 'fn_ty'}}
+ fn_ty{0, 0}; // expected-error {{cannot create object of function type 'fn_ty'}}
+ fn_ty({}); // expected-error {{cannot create object of function type 'fn_ty'}}
+#endif
int v4 = int();
int v5 = int; // expected-error {{expected '(' for function-style cast or type construction}}
typedef int T;
More information about the cfe-commits
mailing list