From 7c50aca2fe36f6daa9bf1c8c428f30e72f96470a Mon Sep 17 00:00:00 2001 From: Anders Carlsson Date: Mon, 15 Oct 2007 20:28:48 +0000 Subject: [PATCH] Add code generation and sema checking for __builtin_va_arg. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@43006 91177308-0d34-0410-b5e6-96231b3b80d8 --- AST/Expr.cpp | 9 +++++++++ AST/StmtPrinter.cpp | 8 ++++++++ CodeGen/CGExprScalar.cpp | 10 ++++++++++ Parse/ParseExpr.cpp | 16 +++++++++------ Sema/Sema.h | 7 +++++++ Sema/SemaDecl.cpp | 26 +++++++++++++++---------- Sema/SemaExpr.cpp | 24 +++++++++++++++++++++++ include/clang/AST/Expr.h | 26 +++++++++++++++++++++++++ include/clang/AST/StmtNodes.def | 1 + include/clang/Basic/DiagnosticKinds.def | 4 +++- include/clang/Parse/Action.h | 7 +++++++ 11 files changed, 121 insertions(+), 17 deletions(-) diff --git a/AST/Expr.cpp b/AST/Expr.cpp index ac8df82aec..eefd8fafe6 100644 --- a/AST/Expr.cpp +++ b/AST/Expr.cpp @@ -1054,6 +1054,15 @@ Stmt::child_iterator ChooseExpr::child_end() { return reinterpret_cast(&SubExprs)+END_EXPR; } +// VAArgExpr +Stmt::child_iterator VAArgExpr::child_begin() { + return reinterpret_cast(&Val); +} + +Stmt::child_iterator VAArgExpr::child_end() { + return reinterpret_cast(&Val)+1; +} + // InitListExpr Stmt::child_iterator InitListExpr::child_begin() { return reinterpret_cast(&InitExprs[0]); diff --git a/AST/StmtPrinter.cpp b/AST/StmtPrinter.cpp index ff4b54bd8d..9b4ad11ec6 100644 --- a/AST/StmtPrinter.cpp +++ b/AST/StmtPrinter.cpp @@ -587,6 +587,14 @@ void StmtPrinter::VisitInitListExpr(InitListExpr* Node) { OS << " }"; } +void StmtPrinter::VisitVAArgExpr(VAArgExpr *Node) { + OS << "va_arg("; + PrintExpr(Node->getSubExpr()); + OS << ", "; + OS << Node->getType().getAsString(); + OS << ")"; +} + // C++ void StmtPrinter::VisitCXXCastExpr(CXXCastExpr *Node) { diff --git a/CodeGen/CGExprScalar.cpp b/CodeGen/CGExprScalar.cpp index 97efa33fc5..e73ce61668 100644 --- a/CodeGen/CGExprScalar.cpp +++ b/CodeGen/CGExprScalar.cpp @@ -16,6 +16,7 @@ #include "clang/AST/AST.h" #include "llvm/Constants.h" #include "llvm/Function.h" +#include "llvm/Intrinsics.h" #include "llvm/Support/Compiler.h" using namespace clang; using namespace CodeGen; @@ -241,6 +242,7 @@ public: // Other Operators. Value *VisitConditionalOperator(const ConditionalOperator *CO); Value *VisitChooseExpr(ChooseExpr *CE); + Value *VisitVAArgExpr(VAArgExpr *VE); Value *VisitObjCStringLiteral(const ObjCStringLiteral *E) { return CGF.EmitObjCStringLiteral(E); } @@ -892,6 +894,14 @@ Value *ScalarExprEmitter::VisitChooseExpr(ChooseExpr *E) { return Visit(CondVal != 0 ? E->getLHS() : E->getRHS()); } +Value *ScalarExprEmitter::VisitVAArgExpr(VAArgExpr *VE) +{ + llvm::Value *ArgValue = EmitLValue(VE->getSubExpr()).getAddress(); + + llvm::Value *V = Builder.CreateVAArg(ArgValue, ConvertType(VE->getType())); + return V; +} + //===----------------------------------------------------------------------===// // Entry Point into this File //===----------------------------------------------------------------------===// diff --git a/Parse/ParseExpr.cpp b/Parse/ParseExpr.cpp index 8a576edab0..c69d4d2d95 100644 --- a/Parse/ParseExpr.cpp +++ b/Parse/ParseExpr.cpp @@ -793,9 +793,9 @@ Parser::ExprResult Parser::ParseBuiltinPrimaryExpression() { switch (T) { default: assert(0 && "Not a builtin primary expression!"); - case tok::kw___builtin_va_arg: - Res = ParseAssignmentExpression(); - if (Res.isInvalid) { + case tok::kw___builtin_va_arg: { + ExprResult Expr = ParseAssignmentExpression(); + if (Expr.isInvalid) { SkipUntil(tok::r_paren); return Res; } @@ -803,11 +803,15 @@ Parser::ExprResult Parser::ParseBuiltinPrimaryExpression() { if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren)) return ExprResult(true); - ParseTypeName(); + TypeTy *Ty = ParseTypeName(); - MatchRHSPunctuation(tok::r_paren, LParenLoc); + if (Tok.isNot(tok::r_paren)) { + Diag(Tok, diag::err_expected_rparen); + return ExprResult(true); + } + Res = Actions.ActOnVAArg(StartLoc, Expr.Val, Ty, ConsumeParen()); break; - + } case tok::kw___builtin_offsetof: { SourceLocation TypeLoc = Tok.getLocation(); TypeTy *Ty = ParseTypeName(); diff --git a/Sema/Sema.h b/Sema/Sema.h index a7db5b9d2a..c45bbf8e5d 100644 --- a/Sema/Sema.h +++ b/Sema/Sema.h @@ -418,6 +418,11 @@ public: ExprTy *cond, ExprTy *expr1, ExprTy *expr2, SourceLocation RPLoc); + // __builtin_va_arg(expr, type) + virtual ExprResult ActOnVAArg(SourceLocation BuiltinLoc, + ExprTy *expr, TypeTy *type, + SourceLocation RPLoc); + /// ActOnCXXCasts - Parse {dynamic,static,reinterpret,const}_cast's. virtual ExprResult ActOnCXXCasts(SourceLocation OpLoc, tok::TokenKind Kind, SourceLocation LAngleBracketLoc, TypeTy *Ty, @@ -624,6 +629,8 @@ private: unsigned NewWidth, bool NewSign, SourceLocation Loc, unsigned DiagID); + void InitBuiltinVaListType(); + //===--------------------------------------------------------------------===// // Extra semantic analysis beyond the C type system private: diff --git a/Sema/SemaDecl.cpp b/Sema/SemaDecl.cpp index 59a2d1d547..62f3fabe7d 100644 --- a/Sema/SemaDecl.cpp +++ b/Sema/SemaDecl.cpp @@ -146,23 +146,29 @@ ScopedDecl *Sema::LookupScopedDecl(IdentifierInfo *II, unsigned NSI, return 0; } +void Sema::InitBuiltinVaListType() +{ + if (!Context.getBuiltinVaListType().isNull()) + return; + + IdentifierInfo *VaIdent = &Context.Idents.get("__builtin_va_list"); + ScopedDecl *VaDecl = LookupScopedDecl(VaIdent, Decl::IDNS_Ordinary, + SourceLocation(), TUScope); + TypedefDecl *VaTypedef = cast(VaDecl); + Context.setBuiltinVaListType(Context.getTypedefType(VaTypedef)); +} + /// LazilyCreateBuiltin - The specified Builtin-ID was first used at file scope. /// lazily create a decl for it. ScopedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid, Scope *S) { Builtin::ID BID = (Builtin::ID)bid; - if ((BID == Builtin::BI__builtin_va_start || + if (BID == Builtin::BI__builtin_va_start || BID == Builtin::BI__builtin_va_copy || - BID == Builtin::BI__builtin_va_end) && - Context.getBuiltinVaListType().isNull()) { - IdentifierInfo *VaIdent = &Context.Idents.get("__builtin_va_list"); - ScopedDecl *VaDecl = LookupScopedDecl(VaIdent, Decl::IDNS_Ordinary, - SourceLocation(), TUScope); - TypedefDecl *VaTypedef = cast(VaDecl); - Context.setBuiltinVaListType(Context.getTypedefType(VaTypedef)); - } - + BID == Builtin::BI__builtin_va_end) + InitBuiltinVaListType(); + QualType R = Context.BuiltinInfo.GetBuiltinType(BID, Context); FunctionDecl *New = new FunctionDecl(SourceLocation(), II, R, FunctionDecl::Extern, false, 0); diff --git a/Sema/SemaExpr.cpp b/Sema/SemaExpr.cpp index 471312baf0..9142a257f4 100644 --- a/Sema/SemaExpr.cpp +++ b/Sema/SemaExpr.cpp @@ -1859,6 +1859,30 @@ Sema::ExprResult Sema::ActOnChooseExpr(SourceLocation BuiltinLoc, ExprTy *cond, return new ChooseExpr(BuiltinLoc, CondExpr, LHSExpr, RHSExpr, resType, RPLoc); } +Sema::ExprResult Sema::ActOnVAArg(SourceLocation BuiltinLoc, + ExprTy *expr, TypeTy *type, + SourceLocation RPLoc) +{ + Expr *E = static_cast(expr); + QualType T = QualType::getFromOpaquePtr(type); + + InitBuiltinVaListType(); + + Sema::AssignmentCheckResult result; + + result = CheckAssignmentConstraints(Context.getBuiltinVaListType(), + E->getType()); + if (result != Compatible) + return Diag(E->getLocStart(), + diag::err_first_argument_to_va_arg_not_of_type_va_list, + E->getType().getAsString(), + E->getSourceRange()); + + // FIXME: Warn if a non-POD type is passed in. + + return new VAArgExpr(BuiltinLoc, E, T, RPLoc); +} + // TODO: Move this to SemaObjC.cpp Sema::ExprResult Sema::ParseObjCStringLiteral(ExprTy *string) { StringLiteral* S = static_cast(string); diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index 4eb96ad89f..26771d6642 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -976,6 +976,32 @@ public: virtual child_iterator child_end(); }; +/// VAArgExpr, used for the builtin function __builtin_va_start. +class VAArgExpr : public Expr { + Expr *Val; + SourceLocation BuiltinLoc, RParenLoc; +public: + VAArgExpr(SourceLocation BLoc, Expr* e, QualType t, SourceLocation RPLoc) + : Expr(VAArgExprClass, t), + Val(e), + BuiltinLoc(BLoc), + RParenLoc(RPLoc) { } + + const Expr *getSubExpr() const { return Val; } + Expr *getSubExpr() { return Val; } + virtual SourceRange getSourceRange() const { + return SourceRange(BuiltinLoc, RParenLoc); + } + static bool classof(const Stmt *T) { + return T->getStmtClass() == VAArgExprClass; + } + static bool classof(const VAArgExpr *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + /// InitListExpr, used for struct and array initializers. class InitListExpr : public Expr { Expr **InitExprs; diff --git a/include/clang/AST/StmtNodes.def b/include/clang/AST/StmtNodes.def index d505312aad..5c4743faa9 100644 --- a/include/clang/AST/StmtNodes.def +++ b/include/clang/AST/StmtNodes.def @@ -66,6 +66,7 @@ STMT(49, ImplicitCastExpr , Expr) STMT(50, CompoundLiteralExpr , Expr) STMT(51, OCUVectorElementExpr , Expr) STMT(52, InitListExpr , Expr) +STMT(53, VAArgExpr , Expr) // GNU Extensions. STMT(55, AddrLabelExpr , Expr) diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index e2b055b783..5325c025ef 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -863,7 +863,9 @@ DIAG(err_va_start_used_in_non_variadic_function, ERROR, "'va_start' used in function with fixed args") DIAG(warn_second_parameter_of_va_start_not_last_named_argument, WARNING, "second parameter of 'va_start' not last named argument") - +DIAG(err_first_argument_to_va_arg_not_of_type_va_list, ERROR, + "first argument to 'va_arg' is of type '%0' and not 'va_list'") + DIAG(warn_return_missing_expr, WARNING, "non-void function '%0' should return a value") DIAG(ext_return_missing_expr, EXTENSION, diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index 2113871f39..cd48862b08 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -425,6 +425,13 @@ public: return 0; } + // __builtin_va_arg(expr, type) + virtual ExprResult ActOnVAArg(SourceLocation BuiltinLoc, + ExprTy *expr, TypeTy *type, + SourceLocation RPLoc) { + return 0; + } + //===------------------------- C++ Expressions --------------------------===// /// ActOnCXXCasts - Parse {dynamic,static,reinterpret,const}_cast's. -- 2.40.0