Implement __builtin_choose_expr.

llvm-svn: 40794
This commit is contained in:
Steve Naroff 2007-08-03 21:21:27 +00:00
parent 65c8a9ee9a
commit 9efdabc565
9 changed files with 109 additions and 11 deletions

View File

@ -487,6 +487,15 @@ void StmtPrinter::VisitTypesCompatibleExpr(TypesCompatibleExpr *Node) {
OS << Node->getArgType2().getAsString() << ")";
}
void StmtPrinter::VisitChooseExpr(ChooseExpr *Node) {
OS << "__builtin_choose_expr(";
PrintExpr(Node->getCond());
OS << ",";
PrintExpr(Node->getLHS());
OS << ",";
PrintExpr(Node->getRHS());
OS << ")";
}
// C++

View File

@ -805,19 +805,35 @@ Parser::ExprResult Parser::ParseBuiltinPrimaryExpression() {
}
}
break;
case tok::kw___builtin_choose_expr:
Res = ParseAssignmentExpression();
case tok::kw___builtin_choose_expr: {
ExprResult Cond = ParseAssignmentExpression();
if (Cond.isInvalid) {
SkipUntil(tok::r_paren);
return Cond;
}
if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren))
return ExprResult(true);
Res = ParseAssignmentExpression();
ExprResult Expr1 = ParseAssignmentExpression();
if (Expr1.isInvalid) {
SkipUntil(tok::r_paren);
return Expr1;
}
if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren))
return ExprResult(true);
Res = ParseAssignmentExpression();
break;
ExprResult Expr2 = ParseAssignmentExpression();
if (Expr2.isInvalid) {
SkipUntil(tok::r_paren);
return Expr2;
}
if (Tok.getKind() != tok::r_paren) {
Diag(Tok, diag::err_expected_rparen);
return ExprResult(true);
}
return Actions.ParseChooseExpr(StartLoc, Cond.Val, Expr1.Val, Expr2.Val,
ConsumeParen());
}
case tok::kw___builtin_types_compatible_p:
TypeTy *Ty1 = ParseTypeName();

View File

@ -285,6 +285,11 @@ public:
virtual ExprResult ParseTypesCompatibleExpr(SourceLocation BuiltinLoc,
TypeTy *arg1, TypeTy *arg2,
SourceLocation RPLoc);
// __builtin_choose_expr(constExpr, expr1, expr2)
virtual ExprResult ParseChooseExpr(SourceLocation BuiltinLoc,
ExprTy *cond, ExprTy *expr1, ExprTy *expr2,
SourceLocation RPLoc);
/// ParseCXXCasts - Parse {dynamic,static,reinterpret,const}_cast's.
virtual ExprResult ParseCXXCasts(SourceLocation OpLoc, tok::TokenKind Kind,

View File

@ -1584,3 +1584,25 @@ Sema::ExprResult Sema::ParseTypesCompatibleExpr(SourceLocation BuiltinLoc,
return new TypesCompatibleExpr(Context.IntTy, BuiltinLoc, argT1, argT2, RPLoc);
}
Sema::ExprResult Sema::ParseChooseExpr(SourceLocation BuiltinLoc, ExprTy *cond,
ExprTy *expr1, ExprTy *expr2,
SourceLocation RPLoc) {
Expr *CondExpr = static_cast<Expr*>(cond);
Expr *LHSExpr = static_cast<Expr*>(expr1);
Expr *RHSExpr = static_cast<Expr*>(expr2);
assert((CondExpr && LHSExpr && RHSExpr) && "Missing type argument(s)");
// The conditional expression is required to be a constant expression.
llvm::APSInt condEval(32);
SourceLocation ExpLoc;
if (!CondExpr->isIntegerConstantExpr(condEval, Context, &ExpLoc))
return Diag(ExpLoc, diag::err_typecheck_choose_expr_requires_constant,
CondExpr->getSourceRange());
// If the condition is > zero, then the AST type is the same as the LSHExpr.
QualType resType = condEval.getZExtValue() ? LHSExpr->getType() :
RHSExpr->getType();
return new ChooseExpr(BuiltinLoc, CondExpr, LHSExpr, RHSExpr, resType, RPLoc);
}

View File

@ -776,6 +776,35 @@ public:
static bool classof(const TypesCompatibleExpr *) { return true; }
};
/// ChooseExpr - GNU builtin-in function __builtin_choose_expr.
/// This AST node is similar to the conditional operator (?:) in C, with
/// the following exceptions:
/// - the test expression much be a constant expression.
/// - the expression returned has it's type unaltered by promotion rules.
/// - does not evaluate the expression that was not chosen.
class ChooseExpr : public Expr {
Expr *Cond, *LHS, *RHS; // First, second, and third arguments.
SourceLocation BuiltinLoc, RParenLoc;
public:
ChooseExpr(SourceLocation BLoc, Expr *cond, Expr *lhs, Expr *rhs, QualType t,
SourceLocation RP)
: Expr(ChooseExprClass, t),
Cond(cond), LHS(lhs), RHS(rhs), BuiltinLoc(BLoc), RParenLoc(RP) {}
Expr *getCond() const { return Cond; }
Expr *getLHS() const { return LHS; }
Expr *getRHS() const { return RHS; }
virtual SourceRange getSourceRange() const {
return SourceRange(BuiltinLoc, RParenLoc);
}
virtual void visit(StmtVisitor &Visitor);
static bool classof(const Stmt *T) {
return T->getStmtClass() == ChooseExprClass;
}
static bool classof(const ChooseExpr *) { return true; }
};
} // end namespace clang
#endif

View File

@ -68,11 +68,12 @@ STMT(49, OCUVectorElementExpr , Expr)
STMT(50, AddrLabelExpr , Expr)
STMT(51, StmtExpr , Expr)
STMT(52, TypesCompatibleExpr , Expr)
STMT(53, ChooseExpr , Expr)
// C++ Expressions.
STMT(53, CXXCastExpr , Expr)
STMT(54, CXXBoolLiteralExpr , Expr)
LAST_EXPR(54)
STMT(54, CXXCastExpr , Expr)
STMT(55, CXXBoolLiteralExpr , Expr)
LAST_EXPR(55)
#undef STMT
#undef FIRST_STMT

View File

@ -652,7 +652,8 @@ DIAG(err_typecheck_cond_incompatible_operands, ERROR,
"incompatible operand types ('%0' and '%1')")
DIAG(ext_typecheck_cond_incompatible_pointers, WARNING,
"pointer type mismatch ('%0' and '%1')")
DIAG(err_typecheck_choose_expr_requires_constant, ERROR,
"'__builtin_choose_expr' requires a constant expression")
DIAG(warn_unused_expr, WARNING,
"expression result unused")

View File

@ -381,6 +381,12 @@ public:
SourceLocation RPLoc) {
return 0;
}
// __builtin_choose_expr(constExpr, expr1, expr2)
virtual ExprResult ParseChooseExpr(SourceLocation BuiltinLoc,
ExprTy *cond, ExprTy *expr1, ExprTy *expr2,
SourceLocation RPLoc) {
return 0;
}
//===------------------------- C++ Expressions --------------------------===//

View File

@ -31,5 +31,14 @@ static void test()
func_choose(a);
func_choose(b);
func_choose(d);
int c;
struct xx { int a; } x, y;
c = __builtin_choose_expr(a+3-7, b, x); // expected-error{{'__builtin_choose_expr' requires a constant expression}}
c = __builtin_choose_expr(0, b, x); // expected-error{{incompatible types assigning 'struct xx' to 'int'}}
c = __builtin_choose_expr(5+3-7, b, x);
y = __builtin_choose_expr(4+3-7, b, x);
}