From bd45d257a404ed1f87090c8a32b5dd75576b7d11 Mon Sep 17 00:00:00 2001 From: Sebastian Redl Date: Thu, 16 Feb 2012 12:59:47 +0000 Subject: [PATCH] Proper checking of list-initializers for array new expressions. This finishes generalized initializer support in Sema. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@150688 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/SemaExprCXX.cpp | 37 +++++++++++++++++++++++-------- test/SemaCXX/new-delete-cxx0x.cpp | 17 ++++++++++++++ 2 files changed, 45 insertions(+), 9 deletions(-) diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 159d4d35af..1f50984996 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -30,6 +30,7 @@ #include "clang/Basic/TargetInfo.h" #include "clang/Lex/Preprocessor.h" #include "TypeLocBuilder.h" +#include "llvm/ADT/APInt.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/ErrorHandling.h" using namespace clang; @@ -976,7 +977,8 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, TypeContainsAuto); } -static bool isLegalArrayNewInitializer(Expr *Init) { +static bool isLegalArrayNewInitializer(CXXNewExpr::InitializationStyle Style, + Expr *Init) { if (!Init) return true; if (ParenListExpr *PLE = dyn_cast(Init)) { @@ -989,6 +991,11 @@ static bool isLegalArrayNewInitializer(Expr *Init) { else if (CXXConstructExpr *CCE = dyn_cast(Init)) return !CCE->isListInitialization() && CCE->getConstructor()->isDefaultConstructor(); + else if (Style == CXXNewExpr::ListInit) { + assert(isa(Init) && + "Shouldn't create list CXXConstructExprs for arrays."); + return true; + } return false; } @@ -1240,14 +1247,26 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, } } + QualType InitType = AllocType; // Array 'new' can't have any initializers except empty parentheses. - if (!isLegalArrayNewInitializer(Initializer) && - (ResultType->isArrayType() || ArraySize)) { - SourceRange InitRange(Inits[0]->getLocStart(), - Inits[NumInits - 1]->getLocEnd()); - - Diag(StartLoc, diag::err_new_array_init_args) << InitRange; - return ExprError(); + // Initializer lists are also allowed, in C++11. Rely on the parser for the + // dialect distinction. + if (ResultType->isArrayType() || ArraySize) { + if (!isLegalArrayNewInitializer(initStyle, Initializer)) { + SourceRange InitRange(Inits[0]->getLocStart(), + Inits[NumInits - 1]->getLocEnd()); + Diag(StartLoc, diag::err_new_array_init_args) << InitRange; + return ExprError(); + } + if (InitListExpr *ILE = dyn_cast_or_null(Initializer)) { + // We do the initialization typechecking against the array type + // corresponding to the number of initializers + 1 (to also check + // default-initialization). + unsigned NumElements = ILE->getNumInits() + 1; + InitType = Context.getConstantArrayType(AllocType, + llvm::APInt(Context.getTypeSize(Context.getSizeType()), NumElements), + ArrayType::Normal, 0); + } } if (!AllocType->isDependentType() && @@ -1270,7 +1289,7 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, DirectInitRange.getEnd()); InitializedEntity Entity - = InitializedEntity::InitializeNew(StartLoc, AllocType); + = InitializedEntity::InitializeNew(StartLoc, InitType); InitializationSequence InitSeq(*this, Entity, Kind, Inits, NumInits); ExprResult FullInit = InitSeq.Perform(*this, Entity, Kind, MultiExprArg(Inits, NumInits)); diff --git a/test/SemaCXX/new-delete-cxx0x.cpp b/test/SemaCXX/new-delete-cxx0x.cpp index 87780ad6b8..c404faba2a 100644 --- a/test/SemaCXX/new-delete-cxx0x.cpp +++ b/test/SemaCXX/new-delete-cxx0x.cpp @@ -7,3 +7,20 @@ void ugly_news(int *ip) { (void)new int[-1]; // expected-warning {{array size is negative}} (void)new int[2000000000]; // expected-warning {{array is too large}} } + + +struct S { + S(int); + S(); + ~S(); +}; + +struct T { // expected-note 2 {{not viable}} + T(int); // expected-note {{not viable}} +}; + +void fn() { + (void) new int[2] {1, 2}; + (void) new S[2] {1, 2}; + (void) new T[2] {1, 2}; // expected-error {{no matching constructor}} +} -- 2.40.0