Add code generation and sema checking for __builtin_va_arg.

llvm-svn: 43006
This commit is contained in:
Anders Carlsson 2007-10-15 20:28:48 +00:00
parent 06a4954e6e
commit 7e13ab88a2
11 changed files with 121 additions and 17 deletions

View File

@ -1054,6 +1054,15 @@ Stmt::child_iterator ChooseExpr::child_end() {
return reinterpret_cast<Stmt**>(&SubExprs)+END_EXPR;
}
// VAArgExpr
Stmt::child_iterator VAArgExpr::child_begin() {
return reinterpret_cast<Stmt**>(&Val);
}
Stmt::child_iterator VAArgExpr::child_end() {
return reinterpret_cast<Stmt**>(&Val)+1;
}
// InitListExpr
Stmt::child_iterator InitListExpr::child_begin() {
return reinterpret_cast<Stmt**>(&InitExprs[0]);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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