]> granicus.if.org Git - clang/commitdiff
Implement __builtin_choose_expr.
authorSteve Naroff <snaroff@apple.com>
Fri, 3 Aug 2007 21:21:27 +0000 (21:21 +0000)
committerSteve Naroff <snaroff@apple.com>
Fri, 3 Aug 2007 21:21:27 +0000 (21:21 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@40794 91177308-0d34-0410-b5e6-96231b3b80d8

AST/StmtPrinter.cpp
Parse/ParseExpr.cpp
Sema/Sema.h
Sema/SemaExpr.cpp
include/clang/AST/Expr.h
include/clang/AST/StmtNodes.def
include/clang/Basic/DiagnosticKinds.def
include/clang/Parse/Action.h
test/Parser/builtin_types_compatible.c

index 1d6fbcc56b72d2662bbdfcc24c15f2e3a76c772d..bdbbc12b1853a6694bb32748eb2253ad59ce7633 100644 (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++
 
index b93234204464694b32cf562a604d4cf3739a388d..75414f7b076abd24dbf89e49ab07eda41703680a 100644 (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();
     
index ff2e5d1fd049425acdae3edc2e351c1820be6ac5..b6d47971f0b5baa2de0039c88835b06a26c1d3d3 100644 (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,
index 2f072f12ab0b4c2f676d545598bc9d5a2f672da6..7a4200632ce7bc9a87f3328c69a0cc6e8e540643 100644 (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);
+}
+
index c9649e3875fcae159280940f795aec46251b94bb..e7d770a2247f7a56d0ca97385f2eda03363ed0d6 100644 (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
index c610f143fca545abe11b7b4d0a2811fec578bd83..ac1ccacc9d6d78c12ef0c3d3a18dfd8703983afa 100644 (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
index acf82964145d8ba7fedddaa0294716da38bac47f..1ede4fd81548882496cd3747dab89e5d39f0c0da 100644 (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")
 
index 2c3ec162e46a0abb94247208569b0e4fe21e6265..088345cb16d2dae01bbe425615b2ccf9d50af252 100644 (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 --------------------------===//
   
index 5dbe0733c2374ac13a42b60023baaf18bbda1ad6..7b066c8e9ade01dbad4788d680f496d45ab52b6a 100644 (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);
+
 }