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.

llvm-svn: 55177
This commit is contained in:
Argyrios Kyrtzidis 2008-08-22 15:38:55 +00:00
parent 5a87265775
commit 857fcc2f8e
14 changed files with 420 additions and 4 deletions

View File

@ -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

View File

@ -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)

View File

@ -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,

View File

@ -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,

View File

@ -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();

View File

@ -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<CastExpr>(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<CastExpr>(this)->getSubExpr();
SourceLocation CastLoc = getLocStart();

View File

@ -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();
}

View File

@ -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) {

View File

@ -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<Expr>(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);
}

View File

@ -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);
}

View File

@ -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());
}

View File

@ -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,

View File

@ -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);
}

View File

@ -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}}
}