From: Argyrios Kyrtzidis Date: Fri, 22 Aug 2008 15:38:55 +0000 (+0000) Subject: Add support for C++'s "type-specifier ( expression-list )" expression: X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=987a14bf5883ef6e5d07f1c83eb6d41a8212a78c;p=clang Add support for C++'s "type-specifier ( expression-list )" expression: -The Parser calls a new "ActOnCXXTypeConstructExpr" action. -Sema, depending on the type and expressions number: -If the type is a class, it will treat it as a class constructor. [TODO] -If there's only one expression (i.e. "int(0.5)" ), creates a new "CXXFunctionalCastExpr" Expr node -If there are no expressions (i.e "int()" ), creates a new "CXXZeroInitValueExpr" Expr node. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@55177 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index 3b15f36277..f0037bf07a 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -169,6 +169,71 @@ public: static CXXDefaultArgExpr* CreateImpl(llvm::Deserializer& D, ASTContext& C); }; + +/// CXXFunctionalCastExpr - [C++ 5.2.3p1] Explicit type conversion +/// (functional notation). +/// Example: "x = int(0.5);" +/// +class CXXFunctionalCastExpr : public CastExpr { + SourceLocation TyBeginLoc; + SourceLocation RParenLoc; +public: + CXXFunctionalCastExpr(QualType ty, SourceLocation tyBeginLoc, Expr *castExpr, + SourceLocation rParenLoc) : + CastExpr(CXXFunctionalCastExprClass, ty, castExpr), + TyBeginLoc(tyBeginLoc), RParenLoc(rParenLoc) {} + + SourceLocation getTypeBeginLoc() const { return TyBeginLoc; } + SourceLocation getRParenLoc() const { return RParenLoc; } + + virtual SourceRange getSourceRange() const { + return SourceRange(TyBeginLoc, RParenLoc); + } + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXFunctionalCastExprClass; + } + static bool classof(const CXXFunctionalCastExpr *) { return true; } + + virtual void EmitImpl(llvm::Serializer& S) const; + static CXXFunctionalCastExpr * + CreateImpl(llvm::Deserializer& D, ASTContext& C); +}; + +/// CXXZeroInitValueExpr - [C++ 5.2.3p2] +/// Expression "T()" which creates a value-initialized Rvalue of non-class +/// type T. +/// +class CXXZeroInitValueExpr : public Expr { + SourceLocation TyBeginLoc; + SourceLocation RParenLoc; + +public: + CXXZeroInitValueExpr(QualType ty, SourceLocation tyBeginLoc, + SourceLocation rParenLoc ) : + Expr(CXXZeroInitValueExprClass, ty), + TyBeginLoc(tyBeginLoc), RParenLoc(rParenLoc) {} + + SourceLocation getTypeBeginLoc() const { return TyBeginLoc; } + SourceLocation getRParenLoc() const { return RParenLoc; } + + virtual SourceRange getSourceRange() const { + return SourceRange(TyBeginLoc, RParenLoc); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXZeroInitValueExprClass; + } + static bool classof(const CXXZeroInitValueExpr *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); + + virtual void EmitImpl(llvm::Serializer& S) const; + static CXXZeroInitValueExpr * + CreateImpl(llvm::Deserializer& D, ASTContext& C); +}; + } // end namespace clang #endif diff --git a/include/clang/AST/StmtNodes.def b/include/clang/AST/StmtNodes.def index 8001d5484d..9a60898428 100644 --- a/include/clang/AST/StmtNodes.def +++ b/include/clang/AST/StmtNodes.def @@ -93,6 +93,8 @@ STMT(60, CXXCastExpr , Expr) STMT(61, CXXBoolLiteralExpr , Expr) STMT(62, CXXThrowExpr , Expr) STMT(63, CXXDefaultArgExpr , Expr) +STMT(64, CXXFunctionalCastExpr, CastExpr) +STMT(65, CXXZeroInitValueExpr , Expr) // Obj-C Expressions. STMT(70, ObjCStringLiteral , Expr) diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index 3e06932b22..82f927db60 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -529,6 +529,8 @@ DIAG(err_no_declarators, ERROR, "declaration does not declare anything") DIAG(err_func_def_no_params, ERROR, "function definition does not declare parameters") +DIAG(err_expected_lparen_after_type, ERROR, + "expected '(' for function-style cast or type construction") //===----------------------------------------------------------------------===// // Semantic Analysis @@ -949,6 +951,16 @@ DIAG(err_invalid_member_use_in_static_method, ERROR, "invalid use of member '%0' in static member function") DIAG(err_invalid_non_static_member_use, ERROR, "invalid use of nonstatic data member '%0'") +DIAG(err_invalid_incomplete_type_use, ERROR, + "invalid use of incomplete type '%0'") +DIAG(err_builtin_func_cast_more_than_one_arg, ERROR, + "function-style cast to a builtin type can only take one argument") +DIAG(err_value_init_for_array_type, ERROR, + "array types cannot be value-initialized") +// Temporary +DIAG(err_unsupported_class_constructor, ERROR, + "class constructors are not supported yet") + // assignment related diagnostics (also for argument passing, returning, etc). DIAG(err_typecheck_convert_incompatible, ERROR, diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index c00fb8067c..ef357c9ae0 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -578,6 +578,20 @@ public: return 0; } + /// ActOnCXXTypeConstructExpr - Parse construction of a specified type. + /// Can be interpreted either as function-style casting ("int(x)") + /// or class type construction ("ClassType(x,y,z)") + /// or creation of a value-initialized type ("int()"). + virtual ExprResult ActOnCXXTypeConstructExpr(SourceRange TypeRange, + TypeTy *TypeRep, + SourceLocation LParenLoc, + ExprTy **Exprs, + unsigned NumExprs, + SourceLocation *CommaLocs, + SourceLocation RParenLoc) { + return 0; + } + //===---------------------------- C++ Classes ---------------------------===// /// ActOnBaseSpecifier - Parsed a base specifier virtual void ActOnBaseSpecifier(DeclTy *classdecl, SourceRange SpecifierRange, diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 2a6e505d64..a2729f0b8b 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -430,6 +430,15 @@ private: // C++ 2.13.5: C++ Boolean Literals ExprResult ParseCXXBoolLiteral(); + //===--------------------------------------------------------------------===// + // C++ 5.2.3: Explicit type conversion (functional notation) + ExprResult ParseCXXTypeConstructExpression(const DeclSpec &DS); + + /// ParseCXXSimpleTypeSpecifier - [C++ 7.1.5.2] Simple type specifiers. + /// This should only be called when the current token is known to be part of + /// simple-type-specifier. + void ParseCXXSimpleTypeSpecifier(DeclSpec &DS); + //===--------------------------------------------------------------------===// // C99 6.7.8: Initialization. ExprResult ParseInitializer(); diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index a3efab637d..9085d2cc0d 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -360,6 +360,7 @@ bool Expr::hasLocalSideEffect() const { return false; } case ExplicitCastExprClass: + case CXXFunctionalCastExprClass: // If this is a cast to void, check the operand. Otherwise, the result of // the cast is unused. if (getType()->isVoidType()) @@ -643,7 +644,8 @@ bool Expr::isConstantExpr(ASTContext &Ctx, SourceLocation *Loc) const { return true; } case ImplicitCastExprClass: - case ExplicitCastExprClass: { + case ExplicitCastExprClass: + case CXXFunctionalCastExprClass: { const Expr *SubExpr = cast(this)->getSubExpr(); SourceLocation CastLoc = getLocStart(); if (!SubExpr->isConstantExpr(Ctx, Loc)) { @@ -931,7 +933,8 @@ bool Expr::isIntegerConstantExpr(llvm::APSInt &Result, ASTContext &Ctx, break; } case ImplicitCastExprClass: - case ExplicitCastExprClass: { + case ExplicitCastExprClass: + case CXXFunctionalCastExprClass: { const Expr *SubExpr = cast(this)->getSubExpr(); SourceLocation CastLoc = getLocStart(); diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index 6069438137..cf85ae2d75 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -45,3 +45,11 @@ Stmt::child_iterator CXXDefaultArgExpr::child_begin() { Stmt::child_iterator CXXDefaultArgExpr::child_end() { return child_iterator(); } + +// CXXZeroInitValueExpr +Stmt::child_iterator CXXZeroInitValueExpr::child_begin() { + return child_iterator(); +} +Stmt::child_iterator CXXZeroInitValueExpr::child_end() { + return child_iterator(); +} diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index 5b4c0ec7ce..a76506007d 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -818,6 +818,17 @@ void StmtPrinter::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *Node) { // Nothing to print: we picked up the default argument } +void StmtPrinter::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node) { + OS << Node->getType().getAsString(); + OS << "("; + PrintExpr(Node->getSubExpr()); + OS << ")"; +} + +void StmtPrinter::VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *Node) { + OS << Node->getType().getAsString() << "()"; +} + // Obj-C void StmtPrinter::VisitObjCStringLiteral(ObjCStringLiteral *Node) { diff --git a/lib/AST/StmtSerialization.cpp b/lib/AST/StmtSerialization.cpp index 9859846292..1c61b66512 100644 --- a/lib/AST/StmtSerialization.cpp +++ b/lib/AST/StmtSerialization.cpp @@ -197,6 +197,12 @@ Stmt* Stmt::Create(Deserializer& D, ASTContext& C) { case CXXDefaultArgExprClass: return CXXDefaultArgExpr::CreateImpl(D, C); + + case CXXFunctionalCastExprClass: + return CXXFunctionalCastExpr::CreateImpl(D, C); + + case CXXZeroInitValueExprClass: + return CXXZeroInitValueExpr::CreateImpl(D, C); } } @@ -1101,3 +1107,33 @@ CXXDefaultArgExpr *CXXDefaultArgExpr::CreateImpl(Deserializer& D, ASTContext& C) D.ReadPtr(Param, false); return new CXXDefaultArgExpr(Param); } + +void CXXFunctionalCastExpr::EmitImpl(Serializer& S) const { + S.Emit(getType()); + S.Emit(TyBeginLoc); + S.Emit(RParenLoc); + S.EmitOwnedPtr(getSubExpr()); +} + +CXXFunctionalCastExpr * +CXXFunctionalCastExpr::CreateImpl(Deserializer& D, ASTContext& C) { + QualType Ty = QualType::ReadVal(D); + SourceLocation TyBeginLoc = SourceLocation::ReadVal(D); + SourceLocation RParenLoc = SourceLocation::ReadVal(D); + Expr* SubExpr = D.ReadOwnedPtr(C); + return new CXXFunctionalCastExpr(Ty, TyBeginLoc, SubExpr, RParenLoc); +} + +void CXXZeroInitValueExpr::EmitImpl(Serializer& S) const { + S.Emit(getType()); + S.Emit(TyBeginLoc); + S.Emit(RParenLoc); +} + +CXXZeroInitValueExpr * +CXXZeroInitValueExpr::CreateImpl(Deserializer& D, ASTContext& C) { + QualType Ty = QualType::ReadVal(D); + SourceLocation TyBeginLoc = SourceLocation::ReadVal(D); + SourceLocation RParenLoc = SourceLocation::ReadVal(D); + return new CXXZeroInitValueExpr(Ty, TyBeginLoc, RParenLoc); +} diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 9eccd06da1..d4b46982ac 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -20,6 +20,7 @@ //===----------------------------------------------------------------------===// #include "clang/Parse/Parser.h" +#include "clang/Parse/DeclSpec.h" #include "clang/Basic/Diagnostic.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/SmallString.h" @@ -372,6 +373,8 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, unsigned MinPrec) { /// [OBJC] '@protocol' '(' identifier ')' /// [OBJC] '@encode' '(' type-name ')' /// [OBJC] objc-string-literal +/// [C++] simple-type-specifier '(' expression-list[opt] ')' [C++ 5.2.3] +/// [C++] typename-specifier '(' expression-list[opt] ')' [TODO] /// [C++] 'const_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1] /// [C++] 'dynamic_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1] /// [C++] 'reinterpret_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1] @@ -446,8 +449,17 @@ Parser::ExprResult Parser::ParseCastExpression(bool isUnaryExpression) { case tok::kw_false: return ParseCXXBoolLiteral(); - case tok::identifier: { // primary-expression: identifier - // constant: enumeration-constant + case tok::identifier: { + if (getLang().CPlusPlus && + Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope)) { + // Handle C++ function-style cast, e.g. "T(4.5)" where T is a typedef for + // double. + goto HandleType; + } + + // primary-expression: identifier + // constant: enumeration-constant + // Consume the identifier so that we can see if it is followed by a '('. // Function designators are allowed to be undeclared (C99 6.5.1p2), so we // need to know whether or not this identifier is a function designator or @@ -545,6 +557,35 @@ Parser::ExprResult Parser::ParseCastExpression(bool isUnaryExpression) { Res = ParseCXXThis(); // This can be followed by postfix-expr pieces. return ParsePostfixExpressionSuffix(Res); + + case tok::kw_char: + case tok::kw_wchar_t: + case tok::kw_bool: + case tok::kw_short: + case tok::kw_int: + case tok::kw_long: + case tok::kw_signed: + case tok::kw_unsigned: + case tok::kw_float: + case tok::kw_double: + case tok::kw_void: + case tok::kw_typeof: { + if (!getLang().CPlusPlus) + goto UnhandledToken; + HandleType: + // postfix-expression: simple-type-specifier '(' expression-list[opt] ')' + // + DeclSpec DS; + ParseCXXSimpleTypeSpecifier(DS); + if (Tok.isNot(tok::l_paren)) + return Diag(Tok.getLocation(), diag::err_expected_lparen_after_type, + DS.getSourceRange()); + + Res = ParseCXXTypeConstructExpression(DS); + // This can be followed by postfix-expr pieces. + return ParsePostfixExpressionSuffix(Res); + } + case tok::at: { SourceLocation AtLoc = ConsumeToken(); return ParseObjCAtExpression(AtLoc); @@ -555,6 +596,7 @@ Parser::ExprResult Parser::ParseCastExpression(bool isUnaryExpression) { return ParsePostfixExpressionSuffix(ParseObjCMessageExpression()); // FALL THROUGH. default: + UnhandledToken: Diag(Tok, diag::err_expected_expression); return ExprResult(true); } diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 45f482792d..bd8e7d510e 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -13,6 +13,7 @@ #include "clang/Basic/Diagnostic.h" #include "clang/Parse/Parser.h" +#include "clang/Parse/DeclSpec.h" using namespace clang; /// ParseCXXCasts - This handles the various ways to cast expressions to another @@ -114,3 +115,130 @@ Parser::ExprResult Parser::ParseCXXThis() { SourceLocation ThisLoc = ConsumeToken(); return Actions.ActOnCXXThis(ThisLoc); } + +/// ParseCXXTypeConstructExpression - Parse construction of a specified type. +/// Can be interpreted either as function-style casting ("int(x)") +/// or class type construction ("ClassType(x,y,z)") +/// or creation of a value-initialized type ("int()"). +/// +/// postfix-expression: [C++ 5.2p1] +/// simple-type-specifier '(' expression-list[opt] ')' [C++ 5.2.3] +/// typename-specifier '(' expression-list[opt] ')' [TODO] +/// +Parser::ExprResult Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) { + Declarator DeclaratorInfo(DS, Declarator::TypeNameContext); + TypeTy *TypeRep = Actions.ActOnTypeName(CurScope, DeclaratorInfo).Val; + + assert(Tok.is(tok::l_paren) && "Expected '('!"); + SourceLocation LParenLoc = ConsumeParen(); + + ExprListTy Exprs; + CommaLocsTy CommaLocs; + + if (Tok.isNot(tok::r_paren)) { + if (ParseExpressionList(Exprs, CommaLocs)) { + SkipUntil(tok::r_paren); + return ExprResult(true); + } + } + + // Match the ')'. + SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); + + assert((Exprs.size() == 0 || Exprs.size()-1 == CommaLocs.size())&& + "Unexpected number of commas!"); + return Actions.ActOnCXXTypeConstructExpr(DS.getSourceRange(), TypeRep, + LParenLoc, + &Exprs[0], Exprs.size(), + &CommaLocs[0], RParenLoc); +} + +/// ParseCXXSimpleTypeSpecifier - [C++ 7.1.5.2] Simple type specifiers. +/// This should only be called when the current token is known to be part of +/// simple-type-specifier. +/// +/// simple-type-specifier: +/// '::'[opt] nested-name-specifier[opt] type-name [TODO] +/// '::'[opt] nested-name-specifier 'template' simple-template-id [TODO] +/// char +/// wchar_t +/// bool +/// short +/// int +/// long +/// signed +/// unsigned +/// float +/// double +/// void +/// [GNU] typeof-specifier +/// [C++0x] auto [TODO] +/// +/// type-name: +/// class-name +/// enum-name +/// typedef-name +/// +void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) { + DS.SetRangeStart(Tok.getLocation()); + const char *PrevSpec; + SourceLocation Loc = Tok.getLocation(); + + switch (Tok.getKind()) { + default: + assert(0 && "Not a simple-type-specifier token!"); + abort(); + + // type-name + case tok::identifier: { + TypeTy *TypeRep = Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope); + assert(TypeRep && "Identifier wasn't a type-name!"); + DS.SetTypeSpecType(DeclSpec::TST_typedef, Loc, PrevSpec, TypeRep); + break; + } + + // builtin types + case tok::kw_short: + DS.SetTypeSpecWidth(DeclSpec::TSW_short, Loc, PrevSpec); + break; + case tok::kw_long: + DS.SetTypeSpecWidth(DeclSpec::TSW_long, Loc, PrevSpec); + break; + case tok::kw_signed: + DS.SetTypeSpecSign(DeclSpec::TSS_signed, Loc, PrevSpec); + break; + case tok::kw_unsigned: + DS.SetTypeSpecSign(DeclSpec::TSS_unsigned, Loc, PrevSpec); + break; + case tok::kw_void: + DS.SetTypeSpecType(DeclSpec::TST_void, Loc, PrevSpec); + break; + case tok::kw_char: + DS.SetTypeSpecType(DeclSpec::TST_char, Loc, PrevSpec); + break; + case tok::kw_int: + DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec); + break; + case tok::kw_float: + DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec); + break; + case tok::kw_double: + DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec); + break; + case tok::kw_wchar_t: + DS.SetTypeSpecType(DeclSpec::TST_wchar, Loc, PrevSpec); + break; + case tok::kw_bool: + DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec); + break; + + // GNU typeof support. + case tok::kw_typeof: + ParseTypeofSpecifier(DS); + DS.Finish(Diags, PP.getSourceManager(), getLang()); + return; + } + DS.SetRangeEnd(Tok.getLocation()); + ConsumeToken(); + DS.Finish(Diags, PP.getSourceManager(), getLang()); +} diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 4bb54824fe..321471d597 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -559,6 +559,18 @@ public: virtual ExprResult ActOnCXXThrow(SourceLocation OpLoc, ExprTy *expr); + /// ActOnCXXTypeConstructExpr - Parse construction of a specified type. + /// Can be interpreted either as function-style casting ("int(x)") + /// or class type construction ("ClassType(x,y,z)") + /// or creation of a value-initialized type ("int()"). + virtual ExprResult ActOnCXXTypeConstructExpr(SourceRange TypeRange, + TypeTy *TypeRep, + SourceLocation LParenLoc, + ExprTy **Exprs, + unsigned NumExprs, + SourceLocation *CommaLocs, + SourceLocation RParenLoc); + // ParseObjCStringLiteral - Parse Objective-C string literals. virtual ExprResult ParseObjCStringLiteral(SourceLocation *AtLocs, ExprTy **Strings, diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 86e334580c..1c723e69b3 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -68,3 +68,67 @@ Action::ExprResult Sema::ActOnCXXThis(SourceLocation ThisLoc) { return Diag(ThisLoc, diag::err_invalid_this_use); } + +/// ActOnCXXTypeConstructExpr - Parse construction of a specified type. +/// Can be interpreted either as function-style casting ("int(x)") +/// or class type construction ("ClassType(x,y,z)") +/// or creation of a value-initialized type ("int()"). +Action::ExprResult +Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep, + SourceLocation LParenLoc, + ExprTy **ExprTys, unsigned NumExprs, + SourceLocation *CommaLocs, + SourceLocation RParenLoc) { + assert(TypeRep && "Missing type!"); + QualType Ty = QualType::getFromOpaquePtr(TypeRep); + Expr **Exprs = (Expr**)ExprTys; + SourceLocation TyBeginLoc = TypeRange.getBegin(); + SourceRange FullRange = SourceRange(TyBeginLoc, RParenLoc); + + if (const RecordType *RT = Ty->getAsRecordType()) { + // C++ 5.2.3p1: + // If the simple-type-specifier specifies a class type, the class type shall + // be complete. + // + if (!RT->getDecl()->isDefinition()) + return Diag(TyBeginLoc, diag::err_invalid_incomplete_type_use, + Ty.getAsString(), FullRange); + + // "class constructors are not supported yet" + return Diag(TyBeginLoc, diag::err_unsupported_class_constructor, FullRange); + } + + // C++ 5.2.3p1: + // 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 (NumExprs == 1) { + if (CheckCastTypes(TypeRange, Ty, Exprs[0])) + return true; + return new CXXFunctionalCastExpr(Ty, TyBeginLoc, Exprs[0], RParenLoc); + } + + // C++ 5.2.3p1: + // If the expression list specifies more than a single value, the type shall + // be a class with a suitably declared constructor. + // + if (NumExprs > 1) + return Diag(CommaLocs[0], diag::err_builtin_func_cast_more_than_one_arg, + FullRange); + + assert(NumExprs == 0 && "Expected 0 expressions"); + + // C++ 5.2.3p2: + // The expression T(), where T is a simple-type-specifier for a non-array + // complete object type or the (possibly cv-qualified) void type, creates an + // rvalue of the specified type, which is value-initialized. + // + if (Ty->isArrayType()) + return Diag(TyBeginLoc, diag::err_value_init_for_array_type, FullRange); + if (Ty->isIncompleteType() && !Ty->isVoidType()) + return Diag(TyBeginLoc, diag::err_invalid_incomplete_type_use, + Ty.getAsString(), FullRange); + + return new CXXZeroInitValueExpr(Ty, TyBeginLoc, RParenLoc); +} diff --git a/test/SemaCXX/type-convert-construct.cpp b/test/SemaCXX/type-convert-construct.cpp new file mode 100644 index 0000000000..4641718bde --- /dev/null +++ b/test/SemaCXX/type-convert-construct.cpp @@ -0,0 +1,10 @@ +// RUN: clang -fsyntax-only -verify %s + +void f() { + float v1 = float(1); + int v2 = typeof(int)(1,2); // expected-error {{function-style cast to a builtin type can only take one argument}} + typedef int arr[]; + int v3 = arr(); // expected-error {{array types cannot be value-initialized}} + int v4 = int(); + int v5 = int; // expected-error {{expected '(' for function-style cast or type construction}} +}