diff options
author | Sebastian Redl <sebastian.redl@getdesigned.at> | 2008-12-02 14:43:59 +0000 |
---|---|---|
committer | Sebastian Redl <sebastian.redl@getdesigned.at> | 2008-12-02 14:43:59 +0000 |
commit | cee63fbf0e64ac526582312bf8cf33263fc5c16e (patch) | |
tree | 274408c3fad7aaaaa463f5f50bce9f516ff3422b | |
parent | 04f9d468f7abfd8a1d85a2ef7cd9c48adb1efa58 (diff) |
Handle new by passing the Declaration to the Action, not a processed type.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@60413 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | Driver/PrintParserCallbacks.cpp | 2 | ||||
-rw-r--r-- | include/clang/AST/ExprCXX.h | 68 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticKinds.def | 15 | ||||
-rw-r--r-- | include/clang/Parse/Action.h | 15 | ||||
-rw-r--r-- | include/clang/Parse/Parser.h | 5 | ||||
-rw-r--r-- | lib/AST/ExprCXX.cpp | 16 | ||||
-rw-r--r-- | lib/AST/StmtPrinter.cpp | 3 | ||||
-rw-r--r-- | lib/AST/StmtSerialization.cpp | 16 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 6 | ||||
-rw-r--r-- | lib/Parse/ParseExprCXX.cpp | 104 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 12 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 108 | ||||
-rw-r--r-- | lib/Sema/SemaType.cpp | 22 | ||||
-rw-r--r-- | test/SemaCXX/new-delete.cpp | 7 | ||||
-rw-r--r-- | www/cxx_status.html | 18 |
15 files changed, 229 insertions, 188 deletions
diff --git a/Driver/PrintParserCallbacks.cpp b/Driver/PrintParserCallbacks.cpp index 02203d356d..2ee113fcda 100644 --- a/Driver/PrintParserCallbacks.cpp +++ b/Driver/PrintParserCallbacks.cpp @@ -168,7 +168,7 @@ namespace { // Type Parsing Callbacks. //===--------------------------------------------------------------------===// - virtual TypeResult ActOnTypeName(Scope *S, Declarator &D, bool CXXNewMode) { + virtual TypeResult ActOnTypeName(Scope *S, Declarator &D) { llvm::cout << __FUNCTION__ << "\n"; return 0; } diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index 201a9331db..2fb55fb4af 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -445,13 +445,16 @@ class CXXNewExpr : public Expr { // Is there an initializer? If not, built-ins are uninitialized, else they're // value-initialized. bool Initializer : 1; + // Do we allocate an array? If so, the first SubExpr is the size expression. + bool Array : 1; // The number of placement new arguments. unsigned NumPlacementArgs : 14; // The number of constructor arguments. This may be 1 even for non-class // types; use the pseudo copy constructor. - unsigned NumConstructorArgs : 15; - // Contains any number of optional placement arguments, and any number of - // optional constructor arguments, in that order. + unsigned NumConstructorArgs : 14; + // Contains an optional array size expression, any number of optional + // placement arguments, and any number of optional constructor arguments, + // in that order. Stmt **SubExprs; // Points to the allocation function used. FunctionDecl *OperatorNew; @@ -461,29 +464,25 @@ class CXXNewExpr : public Expr { // it would still point at the default constructor (even an implicit one). // Must be null for all other types. CXXConstructorDecl *Constructor; - // The type to be allocated. Is either *ty or a VLA of that type. - QualType AllocType; SourceLocation StartLoc; SourceLocation EndLoc; // Deserialization constructor - CXXNewExpr(QualType ty, QualType alloc, bool globalNew, bool parenTypeId, - bool initializer, unsigned numPlacementArgs, - unsigned numConstructorArgs, Stmt **subExprs, - FunctionDecl *operatorNew, FunctionDecl *operatorDelete, - CXXConstructorDecl *constructor, SourceLocation startLoc, - SourceLocation endLoc) + CXXNewExpr(QualType ty, bool globalNew, bool parenTypeId, bool initializer, + bool array, unsigned numPlaceArgs, unsigned numConsArgs, + Stmt **subExprs, FunctionDecl *operatorNew, + FunctionDecl *operatorDelete, CXXConstructorDecl *constructor, + SourceLocation startLoc, SourceLocation endLoc) : Expr(CXXNewExprClass, ty), GlobalNew(globalNew), ParenTypeId(parenTypeId), - Initializer(initializer), NumPlacementArgs(numPlacementArgs), - NumConstructorArgs(numConstructorArgs), SubExprs(subExprs), + Initializer(initializer), Array(array), NumPlacementArgs(numPlaceArgs), + NumConstructorArgs(numConsArgs), SubExprs(subExprs), OperatorNew(operatorNew), OperatorDelete(operatorDelete), - Constructor(constructor), AllocType(alloc), - StartLoc(startLoc), EndLoc(endLoc) + Constructor(constructor), StartLoc(startLoc), EndLoc(endLoc) { } public: CXXNewExpr(bool globalNew, FunctionDecl *operatorNew, Expr **placementArgs, - unsigned numPlaceArgs, bool ParenTypeId, QualType alloc, + unsigned numPlaceArgs, bool ParenTypeId, Expr *arraySize, CXXConstructorDecl *constructor, bool initializer, Expr **constructorArgs, unsigned numConsArgs, FunctionDecl *operatorDelete, QualType ty, @@ -492,20 +491,31 @@ public: delete[] SubExprs; } - QualType getAllocatedType() const { return AllocType; } + QualType getAllocatedType() const { + assert(getType()->isPointerType()); + return getType()->getAsPointerType()->getPointeeType(); + } FunctionDecl *getOperatorNew() const { return OperatorNew; } FunctionDecl *getOperatorDelete() const { return OperatorDelete; } CXXConstructorDecl *getConstructor() const { return Constructor; } + bool isArray() const { return Array; } + Expr *getArraySize() { + return Array ? cast<Expr>(SubExprs[0]) : 0; + } + const Expr *getArraySize() const { + return Array ? cast<Expr>(SubExprs[0]) : 0; + } + unsigned getNumPlacementArgs() const { return NumPlacementArgs; } Expr *getPlacementArg(unsigned i) { assert(i < NumPlacementArgs && "Index out of range"); - return cast<Expr>(SubExprs[i]); + return cast<Expr>(SubExprs[Array + i]); } const Expr *getPlacementArg(unsigned i) const { assert(i < NumPlacementArgs && "Index out of range"); - return cast<Expr>(SubExprs[i]); + return cast<Expr>(SubExprs[Array + i]); } bool isGlobalNew() const { return GlobalNew; } @@ -515,40 +525,40 @@ public: unsigned getNumConstructorArgs() const { return NumConstructorArgs; } Expr *getConstructorArg(unsigned i) { assert(i < NumConstructorArgs && "Index out of range"); - return cast<Expr>(SubExprs[NumPlacementArgs + i]); + return cast<Expr>(SubExprs[Array + NumPlacementArgs + i]); } const Expr *getConstructorArg(unsigned i) const { assert(i < NumConstructorArgs && "Index out of range"); - return cast<Expr>(SubExprs[NumPlacementArgs + i]); + return cast<Expr>(SubExprs[Array + NumPlacementArgs + i]); } typedef ExprIterator arg_iterator; typedef ConstExprIterator const_arg_iterator; arg_iterator placement_arg_begin() { - return SubExprs; + return SubExprs + Array; } arg_iterator placement_arg_end() { - return SubExprs + getNumPlacementArgs(); + return SubExprs + Array + getNumPlacementArgs(); } const_arg_iterator placement_arg_begin() const { - return SubExprs; + return SubExprs + Array; } const_arg_iterator placement_arg_end() const { - return SubExprs + getNumPlacementArgs(); + return SubExprs + Array + getNumPlacementArgs(); } arg_iterator constructor_arg_begin() { - return SubExprs + getNumPlacementArgs(); + return SubExprs + Array + getNumPlacementArgs(); } arg_iterator constructor_arg_end() { - return SubExprs + getNumPlacementArgs() + getNumConstructorArgs(); + return SubExprs + Array + getNumPlacementArgs() + getNumConstructorArgs(); } const_arg_iterator constructor_arg_begin() const { - return SubExprs + getNumPlacementArgs(); + return SubExprs + Array + getNumPlacementArgs(); } const_arg_iterator constructor_arg_end() const { - return SubExprs + getNumPlacementArgs() + getNumConstructorArgs(); + return SubExprs + Array + getNumPlacementArgs() + getNumConstructorArgs(); } virtual SourceRange getSourceRange() const { diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index 57408da6a2..2e76df17ba 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -1228,15 +1228,16 @@ DIAG(err_static_downcast_via_virtual, ERROR, // Other C++ expressions DIAG(err_need_header_before_typeid, ERROR, "you need to include <typeinfo> before using the 'typeid' operator") -// FIXME: merge with %select -DIAG(err_new_function, ERROR, - "cannot allocate function type %0 with new") -DIAG(err_new_incomplete, ERROR, - "cannot allocate incomplete type %0 with new") -DIAG(err_new_reference, ERROR, - "cannot allocate reference type %0 with new") +DIAG(err_static_illegal_in_new, ERROR, + "the 'static' modifier for the array size is not legal in new expressions") +DIAG(err_array_new_needs_size, ERROR, + "array size must be specified in new expressions") +DIAG(err_bad_new_type, ERROR, + "cannot allocate %select{function|incomplete|reference}1 type %0 with new") DIAG(err_new_array_nonconst, ERROR, "only the first dimension of an allocated array may be non-const") +DIAG(err_array_size_not_integral, ERROR, + "array size expression must have integral or enumerated type, not %0") DIAG(err_new_uninitialized_const, ERROR, "must provide an initializer if the allocated object is 'const'") DIAG(err_delete_operand, ERROR, diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index 3b8ab2b055..1695033db8 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -258,10 +258,7 @@ public: //===--------------------------------------------------------------------===// /// ActOnTypeName - A type-name (type-id in C++) was parsed. - /// CXXNewMode is a flag passed by the parser of C++ new-expressions. It - /// specifies that the outermost array (if any) must be treated as a VLA. - virtual TypeResult ActOnTypeName(Scope *S, Declarator &D, - bool CXXNewMode = false) { + virtual TypeResult ActOnTypeName(Scope *S, Declarator &D) { return 0; } @@ -760,18 +757,12 @@ public: /// new was qualified (::new). In a full new like /// @code new (p1, p2) type(c1, c2) @endcode /// the p1 and p2 expressions will be in PlacementArgs and the c1 and c2 - /// expressions in ConstructorArgs. If the type is a dynamic array, Ty will - /// be a variable-length array type, with the outermost dimension to be - /// allocated dynamically. - /// Example: - /// @code new int*[rand()][3] @endcode - /// Here, Ty will be a VLA with size "rand()" and element type "int*[3]". + /// expressions in ConstructorArgs. The type is passed as a declarator. virtual ExprResult ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, SourceLocation PlacementLParen, ExprTy **PlacementArgs, unsigned NumPlaceArgs, SourceLocation PlacementRParen, - bool ParenTypeId, SourceLocation TyStart, - TypeTy *Ty, SourceLocation TyEnd, + bool ParenTypeId, Declarator &D, SourceLocation ConstructorLParen, ExprTy **ConstructorArgs, unsigned NumConsArgs, SourceLocation ConstructorRParen) { diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index feb479c4eb..c9463966a1 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -509,8 +509,7 @@ private: //===--------------------------------------------------------------------===// // C++ 5.3.4 and 5.3.5: C++ new and delete ExprResult ParseCXXNewExpression(); - TypeTy *ParseNewTypeId(); - bool ParseExpressionListOrTypeId(ExprListTy &Exprs, TypeTy *&Ty); + bool ParseExpressionListOrTypeId(ExprListTy &Exprs, Declarator &D); void ParseDirectNewDeclarator(Declarator &D); ExprResult ParseCXXDeleteExpression(); @@ -736,7 +735,7 @@ private: TPResult TryParseBracketDeclarator(); - TypeTy *ParseTypeName(bool CXXNewMode = false); + TypeTy *ParseTypeName(); AttributeList *ParseAttributes(); void ParseTypeofSpecifier(DeclSpec &DS); diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index c0f2985f1e..1bf07c4a63 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -80,30 +80,32 @@ Stmt::child_iterator CXXConditionDeclExpr::child_end() { // CXXNewExpr CXXNewExpr::CXXNewExpr(bool globalNew, FunctionDecl *operatorNew, Expr **placementArgs, unsigned numPlaceArgs, - bool parenTypeId, QualType alloc, + bool parenTypeId, Expr *arraySize, CXXConstructorDecl *constructor, bool initializer, Expr **constructorArgs, unsigned numConsArgs, FunctionDecl *operatorDelete, QualType ty, SourceLocation startLoc, SourceLocation endLoc) : Expr(CXXNewExprClass, ty), GlobalNew(globalNew), ParenTypeId(parenTypeId), - Initializer(initializer), NumPlacementArgs(numPlaceArgs), + Initializer(initializer), Array(arraySize), NumPlacementArgs(numPlaceArgs), NumConstructorArgs(numConsArgs), OperatorNew(operatorNew), - OperatorDelete(operatorDelete), Constructor(constructor), AllocType(alloc), + OperatorDelete(operatorDelete), Constructor(constructor), StartLoc(startLoc), EndLoc(endLoc) { - unsigned TotalSize = NumPlacementArgs + NumConstructorArgs; + unsigned TotalSize = Array + NumPlacementArgs + NumConstructorArgs; SubExprs = new Stmt*[TotalSize]; unsigned i = 0; - for(unsigned j = 0; j < NumPlacementArgs; ++j) + if (Array) + SubExprs[i++] = arraySize; + for (unsigned j = 0; j < NumPlacementArgs; ++j) SubExprs[i++] = placementArgs[j]; - for(unsigned j = 0; j < NumConstructorArgs; ++j) + for (unsigned j = 0; j < NumConstructorArgs; ++j) SubExprs[i++] = constructorArgs[j]; assert(i == TotalSize); } Stmt::child_iterator CXXNewExpr::child_begin() { return &SubExprs[0]; } Stmt::child_iterator CXXNewExpr::child_end() { - return &SubExprs[0] + getNumPlacementArgs() + getNumConstructorArgs(); + return &SubExprs[0] + Array + getNumPlacementArgs() + getNumConstructorArgs(); } // CXXDeleteExpr diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index b6f0707053..445e3e4755 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -953,6 +953,9 @@ void StmtPrinter::VisitCXXNewExpr(CXXNewExpr *E) { } if (E->isParenTypeId()) OS << "("; + // FIXME: This doesn't print the dynamic array size. We'd have to split up + // the allocated type to correctly emit that, but without an ASTContext, + // that's not possible. OS << E->getAllocatedType().getAsString(); if (E->isParenTypeId()) OS << ")"; diff --git a/lib/AST/StmtSerialization.cpp b/lib/AST/StmtSerialization.cpp index 40f5b3ffc5..a8602245f3 100644 --- a/lib/AST/StmtSerialization.cpp +++ b/lib/AST/StmtSerialization.cpp @@ -1444,7 +1444,10 @@ CXXZeroInitValueExpr::CreateImpl(Deserializer& D, ASTContext& C) { void CXXNewExpr::EmitImpl(Serializer& S) const { S.Emit(getType()); - S.Emit(Initializer); + S.EmitBool(GlobalNew); + S.EmitBool(ParenTypeId); + S.EmitBool(Initializer); + S.EmitBool(Array); S.EmitInt(NumPlacementArgs); S.EmitInt(NumConstructorArgs); S.BatchEmitOwnedPtrs(NumPlacementArgs + NumConstructorArgs, SubExprs); @@ -1455,7 +1458,6 @@ void CXXNewExpr::EmitImpl(Serializer& S) const { S.EmitPtr(OperatorNew); S.EmitPtr(OperatorDelete); S.EmitPtr(Constructor); - S.Emit(AllocType); S.Emit(StartLoc); S.Emit(EndLoc); } @@ -1466,19 +1468,19 @@ CXXNewExpr::CreateImpl(Deserializer& D, ASTContext& C) { bool GlobalNew = D.ReadBool(); bool ParenTypeId = D.ReadBool(); bool Initializer = D.ReadBool(); + bool Array = D.ReadBool(); unsigned NumPlacementArgs = D.ReadInt(); unsigned NumConstructorArgs = D.ReadInt(); - unsigned TotalExprs = NumPlacementArgs + NumConstructorArgs; + unsigned TotalExprs = Array + NumPlacementArgs + NumConstructorArgs; Stmt** SubExprs = new Stmt*[TotalExprs]; D.BatchReadOwnedPtrs(TotalExprs, SubExprs, C); FunctionDecl *OperatorNew = D.ReadPtr<FunctionDecl>(); FunctionDecl *OperatorDelete = D.ReadPtr<FunctionDecl>(); CXXConstructorDecl *Constructor = D.ReadPtr<CXXConstructorDecl>(); - QualType AllocType = QualType::ReadVal(D); SourceLocation StartLoc = SourceLocation::ReadVal(D); SourceLocation EndLoc = SourceLocation::ReadVal(D); - return new CXXNewExpr(T, AllocType, GlobalNew, ParenTypeId, Initializer, + return new CXXNewExpr(T, GlobalNew, ParenTypeId, Initializer, Array, NumPlacementArgs, NumConstructorArgs, SubExprs, OperatorNew, OperatorDelete, Constructor, StartLoc, EndLoc); @@ -1486,8 +1488,8 @@ CXXNewExpr::CreateImpl(Deserializer& D, ASTContext& C) { void CXXDeleteExpr::EmitImpl(Serializer& S) const { S.Emit(getType()); - S.Emit(GlobalDelete); - S.Emit(ArrayForm); + S.EmitBool(GlobalDelete); + S.EmitBool(ArrayForm); S.EmitPtr(OperatorDelete); S.EmitOwnedPtr(Argument); S.Emit(Loc); diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 192c70a192..c3bbb52a13 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -28,9 +28,7 @@ using namespace clang; /// specifier-qualifier-list abstract-declarator[opt] /// /// Called type-id in C++. -/// CXXNewMode is a special flag used by the parser of C++ new-expressions. It -/// is simply passed on to ActOnTypeName. -Parser::TypeTy *Parser::ParseTypeName(bool CXXNewMode) { +Parser::TypeTy *Parser::ParseTypeName() { // Parse the common declaration-specifiers piece. DeclSpec DS; ParseSpecifierQualifierList(DS); @@ -39,7 +37,7 @@ Parser::TypeTy *Parser::ParseTypeName(bool CXXNewMode) { Declarator DeclaratorInfo(DS, Declarator::TypeNameContext); ParseDeclarator(DeclaratorInfo); - return Actions.ActOnTypeName(CurScope, DeclaratorInfo, CXXNewMode).Val; + return Actions.ActOnTypeName(CurScope, DeclaratorInfo).Val; } /// ParseAttributes - Parse a non-empty attributes list. diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 09aea03382..d995b887f2 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -645,6 +645,13 @@ Parser::TypeTy *Parser::ParseConversionFunctionId() { /// new-placement: /// '(' expression-list ')' /// +/// new-type-id: +/// type-specifier-seq new-declarator[opt] +/// +/// new-declarator: +/// ptr-operator new-declarator[opt] +/// direct-new-declarator +/// /// new-initializer: /// '(' expression-list[opt] ')' /// [C++0x] braced-init-list [TODO] @@ -671,49 +678,58 @@ Parser::ExprResult Parser::ParseCXXNewExpression() ExprVector PlacementArgs(Actions); SourceLocation PlacementLParen, PlacementRParen; - TypeTy *Ty = 0; - SourceLocation TyStart, TyEnd; bool ParenTypeId; + DeclSpec DS; + Declarator DeclaratorInfo(DS, Declarator::TypeNameContext); if (Tok.is(tok::l_paren)) { // If it turns out to be a placement, we change the type location. PlacementLParen = ConsumeParen(); - TyStart = Tok.getLocation(); - if (ParseExpressionListOrTypeId(PlacementArgs, Ty)) + if (ParseExpressionListOrTypeId(PlacementArgs, DeclaratorInfo)) { + SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true); return true; - TyEnd = Tok.getLocation(); + } PlacementRParen = MatchRHSPunctuation(tok::r_paren, PlacementLParen); - if (PlacementRParen.isInvalid()) + if (PlacementRParen.isInvalid()) { + SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true); return true; + } - if (Ty) { + if (PlacementArgs.empty()) { // Reset the placement locations. There was no placement. PlacementLParen = PlacementRParen = SourceLocation(); ParenTypeId = true; } else { // We still need the type. if (Tok.is(tok::l_paren)) { - ConsumeParen(); - TyStart = Tok.getLocation(); - Ty = ParseTypeName(/*CXXNewMode=*/true); + SourceLocation LParen = ConsumeParen(); + ParseSpecifierQualifierList(DS); + ParseDeclarator(DeclaratorInfo); + MatchRHSPunctuation(tok::r_paren, LParen); ParenTypeId = true; } else { - TyStart = Tok.getLocation(); - Ty = ParseNewTypeId(); + if (ParseCXXTypeSpecifierSeq(DS)) + DeclaratorInfo.setInvalidType(true); + else + ParseDeclaratorInternal(DeclaratorInfo, + &Parser::ParseDirectNewDeclarator); ParenTypeId = false; } - if (!Ty) - return true; - TyEnd = Tok.getLocation(); } } else { - TyStart = Tok.getLocation(); - Ty = ParseNewTypeId(); - if (!Ty) - return true; - TyEnd = Tok.getLocation(); + // A new-type-id is a simplified type-id, where essentially the + // direct-declarator is replaced by a direct-new-declarator. + if (ParseCXXTypeSpecifierSeq(DS)) + DeclaratorInfo.setInvalidType(true); + else + ParseDeclaratorInternal(DeclaratorInfo, + &Parser::ParseDirectNewDeclarator); ParenTypeId = false; } + if (DeclaratorInfo.getInvalidType()) { + SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true); + return true; + } ExprVector ConstructorArgs(Actions); SourceLocation ConstructorLParen, ConstructorRParen; @@ -722,51 +738,25 @@ Parser::ExprResult Parser::ParseCXXNewExpression() ConstructorLParen = ConsumeParen(); if (Tok.isNot(tok::r_paren)) { CommaLocsTy CommaLocs; - if (ParseExpressionList(ConstructorArgs, CommaLocs)) + if (ParseExpressionList(ConstructorArgs, CommaLocs)) { + SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true); return true; + } } ConstructorRParen = MatchRHSPunctuation(tok::r_paren, ConstructorLParen); - if (ConstructorRParen.isInvalid()) + if (ConstructorRParen.isInvalid()) { + SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true); return true; + } } return Actions.ActOnCXXNew(Start, UseGlobal, PlacementLParen, PlacementArgs.take(), PlacementArgs.size(), - PlacementRParen, ParenTypeId, TyStart, Ty, TyEnd, + PlacementRParen, ParenTypeId, DeclaratorInfo, ConstructorLParen, ConstructorArgs.take(), ConstructorArgs.size(), ConstructorRParen); } -/// ParseNewTypeId - Parses a type ID as it appears in a new expression. -/// The most interesting part of this is the new-declarator, which can be a -/// multi-dimensional array, of which the first has a non-constant expression as -/// the size, e.g. -/// @code new int[runtimeSize()][2][2] @endcode -/// -/// new-type-id: -/// type-specifier-seq new-declarator[opt] -/// -/// new-declarator: -/// ptr-operator new-declarator[opt] -/// direct-new-declarator -/// -Parser::TypeTy * Parser::ParseNewTypeId() -{ - DeclSpec DS; - if (ParseCXXTypeSpecifierSeq(DS)) - return 0; - - // A new-declarator is a simplified version of a declarator. We use - // ParseDeclaratorInternal, but pass our own direct declarator parser, - // one that parses a direct-new-declarator. - Declarator DeclaratorInfo(DS, Declarator::TypeNameContext); - ParseDeclaratorInternal(DeclaratorInfo, &Parser::ParseDirectNewDeclarator); - - TypeTy *Ty = Actions.ActOnTypeName(CurScope, DeclaratorInfo, - /*CXXNewMode=*/true).Val; - return DeclaratorInfo.getInvalidType() ? 0 : Ty; -} - /// ParseDirectNewDeclarator - Parses a direct-new-declarator. Intended to be /// passed to ParseDeclaratorInternal. /// @@ -806,12 +796,14 @@ void Parser::ParseDirectNewDeclarator(Declarator &D) /// new-placement: /// '(' expression-list ')' /// -bool Parser::ParseExpressionListOrTypeId(ExprListTy &PlacementArgs, TypeTy *&Ty) +bool Parser::ParseExpressionListOrTypeId(ExprListTy &PlacementArgs, + Declarator &D) { // The '(' was already consumed. if (isTypeIdInParens()) { - Ty = ParseTypeName(/*CXXNewMode=*/true); - return Ty == 0; + ParseSpecifierQualifierList(D.getMutableDeclSpec()); + ParseDeclarator(D); + return D.getInvalidType(); } // It's not a type, it has to be an expression list. diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 6f1cf8883b..7f3d0f4d2f 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -245,16 +245,14 @@ public: // QualType ConvertDeclSpecToType(const DeclSpec &DS); void ProcessTypeAttributeList(QualType &Result, const AttributeList *AL); - QualType GetTypeForDeclarator(Declarator &D, Scope *S, - bool CXXNewMode = false); + QualType GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip = 0); DeclarationName GetNameForDeclarator(Declarator &D); QualType ObjCGetTypeForMethodDefinition(DeclTy *D); bool UnwrapSimilarPointerTypes(QualType& T1, QualType& T2); - virtual TypeResult ActOnTypeName(Scope *S, Declarator &D, - bool CXXNewMode = false); + virtual TypeResult ActOnTypeName(Scope *S, Declarator &D); //===--------------------------------------------------------------------===// // Symbol table / Decl tracking callbacks: SemaDecl.cpp. @@ -828,13 +826,11 @@ public: SourceLocation PlacementLParen, ExprTy **PlacementArgs, unsigned NumPlaceArgs, SourceLocation PlacementRParen, - bool ParenTypeId, SourceLocation TyStart, - TypeTy *Ty, SourceLocation TyEnd, + bool ParenTypeId, Declarator &D, SourceLocation ConstructorLParen, ExprTy **ConstructorArgs, unsigned NumConsArgs, SourceLocation ConstructorRParen); - bool CheckAllocatedType(QualType AllocType, SourceLocation StartLoc, - const SourceRange &TyR); + bool CheckAllocatedType(QualType AllocType, const Declarator &D); /// ActOnCXXDelete - Parsed a C++ 'delete' expression virtual ExprResult ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 3633da89bc..bfc367dd58 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -180,30 +180,60 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, SourceLocation PlacementLParen, ExprTy **PlacementArgs, unsigned NumPlaceArgs, SourceLocation PlacementRParen, bool ParenTypeId, - SourceLocation TyStart, TypeTy *Ty, SourceLocation TyEnd, - SourceLocation ConstructorLParen, + Declarator &D, SourceLocation ConstructorLParen, ExprTy **ConstructorArgs, unsigned NumConsArgs, SourceLocation ConstructorRParen) { - QualType AllocType = QualType::getFromOpaquePtr(Ty); - QualType CheckType = AllocType; - // To leverage the existing parser as much as possible, array types are - // parsed as VLAs. Unwrap for checking. - if (const VariableArrayType *VLA = Context.getAsVariableArrayType(AllocType)) - CheckType = VLA->getElementType(); - - // Validate the type, and unwrap an array if any. - if (CheckAllocatedType(CheckType, StartLoc, SourceRange(TyStart, TyEnd))) + // FIXME: Throughout this function, we have rather bad location information. + // Implementing Declarator::getSourceRange() would go a long way toward + // fixing that. + + Expr *ArraySize = 0; + unsigned Skip = 0; + // If the specified type is an array, unwrap it and save the expression. + if (D.getNumTypeObjects() > 0 && + D.getTypeObject(0).Kind == DeclaratorChunk::Array) { + DeclaratorChunk &Chunk = D.getTypeObject(0); + if (Chunk.Arr.hasStatic) + return Diag(Chunk.Loc, diag::err_static_illegal_in_new); + if (!Chunk.Arr.NumElts) + return Diag(Chunk.Loc, diag::err_array_new_needs_size); + ArraySize = static_cast<Expr*>(Chunk.Arr.NumElts); + Skip = 1; + } + + QualType AllocType = GetTypeForDeclarator(D, /*Scope=*/0, Skip); + if (D.getInvalidType()) + return true; + + if (CheckAllocatedType(AllocType, D)) return true; - QualType ResultType = Context.getPointerType(CheckType); + QualType ResultType = Context.getPointerType(AllocType); // That every array dimension except the first is constant was already // checked by the type check above. + // C++ 5.3.4p6: "The expression in a direct-new-declarator shall have integral // or enumeration type with a non-negative value." - // This was checked by ActOnTypeName, since C99 has the same restriction on - // VLA expressions. + if (ArraySize) { + QualType SizeType = ArraySize->getType(); + if (!SizeType->isIntegralType() && !SizeType->isEnumeralType()) + return Diag(ArraySize->getSourceRange().getBegin(), + diag::err_array_size_not_integral) + << SizeType << ArraySize->getSourceRange(); + // Let's see if this is a constant < 0. If so, we reject it out of hand. + // We don't care about special rules, so we tell the machinery it's not + // evaluated - it gives us a result in more cases. + llvm::APSInt Value; + if (ArraySize->isIntegerConstantExpr(Value, Context, 0, false)) { + if (Value < llvm::APSInt( + llvm::APInt::getNullValue(Value.getBitWidth()), false)) + return Diag(ArraySize->getSourceRange().getBegin(), + diag::err_typecheck_negative_array_size) + << ArraySize->getSourceRange(); + } + } // --- Choosing an allocation function --- // C++ 5.3.4p8 - 14 & 18 @@ -239,12 +269,14 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, // 2) Otherwise, the object is direct-initialized. CXXConstructorDecl *Constructor = 0; Expr **ConsArgs = (Expr**)ConstructorArgs; - if (const RecordType *RT = CheckType->getAsRecordType()) { + if (const RecordType *RT = AllocType->getAsRecordType()) { // FIXME: This is incorrect for when there is an empty initializer and // no user-defined constructor. Must zero-initialize, not default-construct. Constructor = PerformInitializationByConstructor( - CheckType, ConsArgs, NumConsArgs, - TyStart, SourceRange(TyStart, ConstructorRParen), + AllocType, ConsArgs, NumConsArgs, + D.getDeclSpec().getSourceRange().getBegin(), + SourceRange(D.getDeclSpec().getSourceRange().getBegin(), + ConstructorRParen), RT->getDecl()->getDeclName(), NumConsArgs != 0 ? IK_Direct : IK_Default); if (!Constructor) @@ -252,9 +284,9 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, } else { if (!Init) { // FIXME: Check that no subpart is const. - if (CheckType.isConstQualified()) { + if (AllocType.isConstQualified()) { Diag(StartLoc, diag::err_new_uninitialized_const) - << SourceRange(StartLoc, TyEnd); + << D.getSourceRange(); return true; } } else if (NumConsArgs == 0) { @@ -262,8 +294,8 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, } else if (NumConsArgs == 1) { // Object is direct-initialized. // FIXME: WHAT DeclarationName do we pass in here? - if (CheckInitializerTypes(ConsArgs[0], CheckType, StartLoc, - DeclarationName() /*CheckType.getAsString()*/)) + if (CheckInitializerTypes(ConsArgs[0], AllocType, StartLoc, + DeclarationName() /*AllocType.getAsString()*/)) return true; } else { Diag(StartLoc, diag::err_builtin_direct_init_more_than_one_arg) @@ -274,16 +306,15 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, // FIXME: Also check that the destructor is accessible. (C++ 5.3.4p16) return new CXXNewExpr(UseGlobal, OperatorNew, PlaceArgs, NumPlaceArgs, - ParenTypeId, AllocType, Constructor, Init, + ParenTypeId, ArraySize, Constructor, Init, ConsArgs, NumConsArgs, OperatorDelete, ResultType, - StartLoc, Init ? ConstructorRParen : TyEnd); + StartLoc, Init ? ConstructorRParen : SourceLocation()); } /// CheckAllocatedType - Checks that a type is suitable as the allocated type /// in a new-expression. /// dimension off and stores the size expression in ArraySize. -bool Sema::CheckAllocatedType(QualType AllocType, SourceLocation StartLoc, - const SourceRange &TyR) +bool Sema::CheckAllocatedType(QualType AllocType, const Declarator &D) { // C++ 5.3.4p1: "[The] type shall be a complete object type, but not an // abstract class type or array thereof. @@ -291,29 +322,34 @@ bool Sema::CheckAllocatedType(QualType AllocType, SourceLocation StartLoc, // FIXME: Under C++ semantics, an incomplete object type is still an object // type. This code assumes the C semantics, where it's not. if (!AllocType->isObjectType()) { - diag::kind msg; + unsigned type; // For the select in the message. if (AllocType->isFunctionType()) { - msg = diag::err_new_function; + type = 0; } else if(AllocType->isIncompleteType()) { - msg = diag::err_new_incomplete; - } else if(AllocType->isReferenceType()) { - msg = diag::err_new_reference; + type = 1; } else { - assert(false && "Unexpected type class"); - return true; + assert(AllocType->isReferenceType() && "What else could it be?"); + type = 2; } - Diag(StartLoc, msg) << AllocType << TyR; + SourceRange TyR = D.getDeclSpec().getSourceRange(); + // FIXME: This is very much a guess and won't work for, e.g., pointers. + if (D.getNumTypeObjects() > 0) + TyR.setEnd(D.getTypeObject(0).Loc); + Diag(TyR.getBegin(), diag::err_bad_new_type) + << AllocType.getAsString() << type << TyR; return true; |