From: Chris Lattner Date: Tue, 24 Jul 2007 16:58:17 +0000 (+0000) Subject: implement ast building and trivial semantic analysis of stmt exprs. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ab18c4c0ac1a46a38aa84c2c8ea485612e21a614;p=clang implement ast building and trivial semantic analysis of stmt exprs. This implements test/Sema/stmt_exprs.c git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@40465 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/AST/StmtPrinter.cpp b/AST/StmtPrinter.cpp index 64e94f9048..2c4b21eb85 100644 --- a/AST/StmtPrinter.cpp +++ b/AST/StmtPrinter.cpp @@ -468,9 +468,15 @@ void StmtPrinter::VisitConditionalOperator(ConditionalOperator *Node) { void StmtPrinter::VisitAddrLabel(AddrLabel *Node) { OS << "&&" << Node->getLabel()->getName(); - } +void StmtPrinter::VisitStmtExpr(StmtExpr *E) { + OS << "("; + PrintRawCompoundStmt(E->getSubStmt()); + OS << ")"; +} + + // C++ void StmtPrinter::VisitCXXCastExpr(CXXCastExpr *Node) { diff --git a/Parse/ParseExpr.cpp b/Parse/ParseExpr.cpp index 467dc1dcf3..de0a2a2d67 100644 --- a/Parse/ParseExpr.cpp +++ b/Parse/ParseExpr.cpp @@ -539,7 +539,7 @@ Parser::ExprResult Parser::ParseCastExpression(bool isUnaryExpression) { case tok::kw___real: // unary-expression: '__real' cast-expression [GNU] case tok::kw___imag: // unary-expression: '__imag' cast-expression [GNU] case tok::kw___extension__:{//unary-expression:'__extension__' cast-expr [GNU] - // FIXME: Extension not handled correctly here! + // FIXME: Extension should silence extwarns in subexpressions. SourceLocation SavedLoc = ConsumeToken(); Res = ParseCastExpression(false); if (!Res.isInvalid) @@ -853,15 +853,19 @@ Parser::ExprResult Parser::ParseParenExpression(ParenParseOption &ExprType, SourceLocation &RParenLoc) { assert(Tok.getKind() == tok::l_paren && "Not a paren expr!"); SourceLocation OpenLoc = ConsumeParen(); - ExprResult Result(false); + ExprResult Result(true); CastTy = 0; if (ExprType >= CompoundStmt && Tok.getKind() == tok::l_brace && !getLang().NoExtensions) { Diag(Tok, diag::ext_gnu_statement_expr); - ParseCompoundStatement(); + Parser::StmtResult Stmt = ParseCompoundStatement(); ExprType = CompoundStmt; - // TODO: Build AST for GNU compound stmt. + + // If the substmt parsed correctly, build the AST node. + if (!Stmt.isInvalid && Tok.getKind() == tok::r_paren) + Result = Actions.ParseStmtExpr(OpenLoc, Stmt.Val, Tok.getLocation()); + } else if (ExprType >= CompoundLiteral && isTypeSpecifierQualifier()) { // Otherwise, this is a compound literal expression or cast expression. TypeTy *Ty = ParseTypeName(); diff --git a/Sema/Sema.h b/Sema/Sema.h index 39a3cc08f1..e1857b7583 100644 --- a/Sema/Sema.h +++ b/Sema/Sema.h @@ -271,6 +271,9 @@ public: virtual ExprResult ParseAddrLabel(SourceLocation OpLoc, SourceLocation LabLoc, IdentifierInfo *LabelII); + virtual ExprResult ParseStmtExpr(SourceLocation LPLoc, StmtTy *SubStmt, + SourceLocation RPLoc); // "({..})" + /// ParseCXXCasts - Parse {dynamic,static,reinterpret,const}_cast's. virtual ExprResult ParseCXXCasts(SourceLocation OpLoc, tok::TokenKind Kind, SourceLocation LAngleBracketLoc, TypeTy *Ty, diff --git a/Sema/SemaExpr.cpp b/Sema/SemaExpr.cpp index 3bad52a475..7e0b641276 100644 --- a/Sema/SemaExpr.cpp +++ b/Sema/SemaExpr.cpp @@ -1476,3 +1476,26 @@ Sema::ExprResult Sema::ParseAddrLabel(SourceLocation OpLoc, Context.getPointerType(Context.VoidTy)); } +Sema::ExprResult Sema::ParseStmtExpr(SourceLocation LPLoc, StmtTy *substmt, + SourceLocation RPLoc) { // "({..})" + Stmt *SubStmt = static_cast(substmt); + assert(SubStmt && isa(SubStmt) && "Invalid action invocation!"); + CompoundStmt *Compound = cast(SubStmt); + + // FIXME: there are a variety of strange constraints to enforce here, for + // example, it is not possible to goto into a stmt expression apparently. + // More semantic analysis is needed. + + // FIXME: the last statement in the compount stmt has its value used. We + // should not warn about it being unused. + + // If there are sub stmts in the compound stmt, take the type of the last one + // as the type of the stmtexpr. + QualType Ty = Context.VoidTy; + + if (!Compound->body_empty()) + if (Expr *LastExpr = dyn_cast(Compound->body_back())) + Ty = LastExpr->getType(); + + return new StmtExpr(Compound, Ty, LPLoc, RPLoc); +} diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index 73dce8ede4..cf5ee87c79 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -134,7 +134,7 @@ public: static bool classof(const DeclRefExpr *) { return true; } }; -// PreDefinedExpr - [C99 6.4.2.2] - A pre-defined identifier such as __func__ +/// PreDefinedExpr - [C99 6.4.2.2] - A pre-defined identifier such as __func__. class PreDefinedExpr : public Expr { public: enum IdentType { @@ -661,7 +661,33 @@ public: } static bool classof(const AddrLabel *) { return true; } }; + +/// StmtExpr - This is the GNU Statement Expression extension: ({int X=4; X;}). +/// The StmtExpr contains a single CompoundStmt node, which it evaluates and +/// takes the value of the last subexpression. +class StmtExpr : public Expr { + CompoundStmt *SubStmt; + SourceLocation LParenLoc, RParenLoc; +public: + StmtExpr(CompoundStmt *substmt, QualType T, + SourceLocation lp, SourceLocation rp) + : Expr(StmtExprClass, T), SubStmt(substmt), LParenLoc(lp), RParenLoc(rp) { + } + + CompoundStmt *getSubStmt() { return SubStmt; } + const CompoundStmt *getSubStmt() const { return SubStmt; } + + virtual SourceRange getSourceRange() const { + return SourceRange(LParenLoc, RParenLoc); + } + virtual void visit(StmtVisitor &Visitor); + static bool classof(const Stmt *T) { + return T->getStmtClass() == StmtExprClass; + } + static bool classof(const StmtExpr *) { return true; } +}; + } // end namespace clang #endif diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h index 4fcf7aecb8..ef6e739447 100644 --- a/include/clang/AST/Stmt.h +++ b/include/clang/AST/Stmt.h @@ -107,13 +107,17 @@ public: CompoundStmt(Stmt **StmtStart, unsigned NumStmts) : Stmt(CompoundStmtClass), Body(StmtStart, StmtStart+NumStmts) {} + bool body_empty() const { return Body.empty(); } + typedef llvm::SmallVector::iterator body_iterator; body_iterator body_begin() { return Body.begin(); } body_iterator body_end() { return Body.end(); } + Stmt *body_back() { return Body.back(); } typedef llvm::SmallVector::const_iterator const_body_iterator; const_body_iterator body_begin() const { return Body.begin(); } const_body_iterator body_end() const { return Body.end(); } + const Stmt *body_back() const { return Body.back(); } void push_back(Stmt *S) { Body.push_back(S); } diff --git a/include/clang/AST/StmtNodes.def b/include/clang/AST/StmtNodes.def index b4c220c0e2..b99d225d2a 100644 --- a/include/clang/AST/StmtNodes.def +++ b/include/clang/AST/StmtNodes.def @@ -65,11 +65,12 @@ STMT(48, CompoundLiteralExpr , Expr) // GNU Extensions. STMT(49, AddrLabel , Expr) +STMT(50, StmtExpr , Expr) // C++ Expressions. -STMT(50, CXXCastExpr , Expr) -STMT(51, CXXBoolLiteralExpr , Expr) -LAST_EXPR(51) +STMT(51, CXXCastExpr , Expr) +STMT(52, CXXBoolLiteralExpr , Expr) +LAST_EXPR(52) #undef STMT #undef FIRST_STMT diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index 4cb49b2ac6..d9e3e12c4c 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -364,11 +364,19 @@ public: return 0; } + //===---------------------- GNU Extension Expressions -------------------===// + virtual ExprResult ParseAddrLabel(SourceLocation OpLoc, SourceLocation LabLoc, IdentifierInfo *LabelII) { // "&&foo" return 0; } + virtual ExprResult ParseStmtExpr(SourceLocation LPLoc, StmtTy *SubStmt, + SourceLocation RPLoc) { // "({..})" + return 0; + } + + //===------------------------- C++ Expressions --------------------------===// /// ParseCXXCasts - Parse {dynamic,static,reinterpret,const}_cast's. virtual ExprResult ParseCXXCasts(SourceLocation OpLoc, tok::TokenKind Kind, diff --git a/test/Sema/stmt_exprs.c b/test/Sema/stmt_exprs.c new file mode 100644 index 0000000000..34186a8d5c --- /dev/null +++ b/test/Sema/stmt_exprs.c @@ -0,0 +1,12 @@ +// clang %s -fsyntax-only + +typedef unsigned __uint32_t; + +#define __byte_swap_int_var(x) \ +__extension__ ({ register __uint32_t __X = (x); \ + __asm ("bswap %0" : "+r" (__X)); \ + __X; }) + +int test(int _x) { + return (__byte_swap_int_var(_x)); +}