summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/AST/StmtPrinter.cpp9
-rw-r--r--clang/Parse/ParseExpr.cpp30
-rw-r--r--clang/Sema/Sema.h5
-rw-r--r--clang/Sema/SemaExpr.cpp22
-rw-r--r--clang/include/clang/AST/Expr.h29
-rw-r--r--clang/include/clang/AST/StmtNodes.def7
-rw-r--r--clang/include/clang/Basic/DiagnosticKinds.def3
-rw-r--r--clang/include/clang/Parse/Action.h6
-rw-r--r--clang/test/Parser/builtin_types_compatible.c9
9 files changed, 109 insertions, 11 deletions
diff --git a/clang/AST/StmtPrinter.cpp b/clang/AST/StmtPrinter.cpp
index 1d6fbcc56b7..bdbbc12b185 100644
--- a/clang/AST/StmtPrinter.cpp
+++ b/clang/AST/StmtPrinter.cpp
@@ -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++
diff --git a/clang/Parse/ParseExpr.cpp b/clang/Parse/ParseExpr.cpp
index b9323420446..75414f7b076 100644
--- a/clang/Parse/ParseExpr.cpp
+++ b/clang/Parse/ParseExpr.cpp
@@ -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();
diff --git a/clang/Sema/Sema.h b/clang/Sema/Sema.h
index ff2e5d1fd04..b6d47971f0b 100644
--- a/clang/Sema/Sema.h
+++ b/clang/Sema/Sema.h
@@ -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,
diff --git a/clang/Sema/SemaExpr.cpp b/clang/Sema/SemaExpr.cpp
index 2f072f12ab0..7a4200632ce 100644
--- a/clang/Sema/SemaExpr.cpp
+++ b/clang/Sema/SemaExpr.cpp
@@ -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);
+}
+
diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h
index c9649e3875f..e7d770a2247 100644
--- a/clang/include/clang/AST/Expr.h
+++ b/clang/include/clang/AST/Expr.h
@@ -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
diff --git a/clang/include/clang/AST/StmtNodes.def b/clang/include/clang/AST/StmtNodes.def
index c610f143fca..ac1ccacc9d6 100644
--- a/clang/include/clang/AST/StmtNodes.def
+++ b/clang/include/clang/AST/StmtNodes.def
@@ -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
diff --git a/clang/include/clang/Basic/DiagnosticKinds.def b/clang/include/clang/Basic/DiagnosticKinds.def
index acf82964145..1ede4fd8154 100644
--- a/clang/include/clang/Basic/DiagnosticKinds.def
+++ b/clang/include/clang/Basic/DiagnosticKinds.def
@@ -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")
diff --git a/clang/include/clang/Parse/Action.h b/clang/include/clang/Parse/Action.h
index 2c3ec162e46..088345cb16d 100644
--- a/clang/include/clang/Parse/Action.h
+++ b/clang/include/clang/Parse/Action.h
@@ -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 --------------------------===//
diff --git a/clang/test/Parser/builtin_types_compatible.c b/clang/test/Parser/builtin_types_compatible.c
index 5dbe0733c23..7b066c8e9ad 100644
--- a/clang/test/Parser/builtin_types_compatible.c
+++ b/clang/test/Parser/builtin_types_compatible.c
@@ -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);
+
}
OpenPOWER on IntegriCloud