]> granicus.if.org Git - clang/commitdiff
Fix sema support for the gnu ?: expression with a
authorChris Lattner <sabre@nondot.org>
Mon, 26 Nov 2007 01:40:58 +0000 (01:40 +0000)
committerChris Lattner <sabre@nondot.org>
Mon, 26 Nov 2007 01:40:58 +0000 (01:40 +0000)
missing middle expression, and fix a codegen bug where
we didn't correctly promote the condition to the right
result type.  This fixes PR1824.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@44322 91177308-0d34-0410-b5e6-96231b3b80d8

CodeGen/CGExprScalar.cpp
Sema/SemaExpr.cpp
test/CodeGen/conditional-gnu-ext.c [new file with mode: 0644]

index 669928b6f07dfbfa7dadec91344e48c8a1d79ccf..f0a75dbf136656afd9db5ae345367b140964a818 100644 (file)
@@ -884,13 +884,23 @@ VisitConditionalOperator(const ConditionalOperator *E) {
   llvm::BasicBlock *RHSBlock = new llvm::BasicBlock("cond.:");
   llvm::BasicBlock *ContBlock = new llvm::BasicBlock("cond.cont");
   
-  Value *Cond = CGF.EvaluateExprAsBool(E->getCond());
-  Builder.CreateCondBr(Cond, LHSBlock, RHSBlock);
+  // Evaluate the conditional, then convert it to bool.  We do this explicitly
+  // because we need the unconverted value if this is a GNU ?: expression with
+  // missing middle value.
+  Value *CondVal = CGF.EmitScalarExpr(E->getCond());
+  Value *CondBoolVal = CGF.EmitScalarConversion(CondVal, E->getCond()->getType(), 
+                                                CGF.getContext().BoolTy);
+  Builder.CreateCondBr(CondBoolVal, LHSBlock, RHSBlock);
   
   CGF.EmitBlock(LHSBlock);
   
   // Handle the GNU extension for missing LHS.
-  Value *LHS = E->getLHS() ? Visit(E->getLHS()) : Cond;
+  Value *LHS;
+  if (E->getLHS())
+    LHS = Visit(E->getLHS());
+  else    // Perform promotions, to handle cases like "short ?: int"
+    LHS = EmitScalarConversion(CondVal, E->getCond()->getType(), E->getType());
+  
   Builder.CreateBr(ContBlock);
   LHSBlock = Builder.GetInsertBlock();
   
index a9cd41580bbbda0feb48d0ab70b20f904bf89b30..dcec7253eac0475946023b8f1f43cd3fc23f6c79 100644 (file)
@@ -738,6 +738,8 @@ static void promoteExprToType(Expr *&expr, QualType type) {
   return;
 }
 
+/// Note that lex is not null here, even if this is the gnu "x ?: y" extension.
+/// In that case, lex = cond.
 inline QualType Sema::CheckConditionalOperands( // C99 6.5.15
   Expr *&cond, Expr *&lex, Expr *&rex, SourceLocation questionLoc) {
   UsualUnaryConversions(cond);
@@ -760,8 +762,7 @@ inline QualType Sema::CheckConditionalOperands( // C99 6.5.15
   }
   if (const RecordType *LHSRT = lexT->getAsRecordType()) {    // C99 6.5.15p3
     if (const RecordType *RHSRT = rexT->getAsRecordType()) {
-      
-      if (LHSRT->getDecl()->getIdentifier() ==RHSRT->getDecl()->getIdentifier())
+      if (LHSRT->getDecl() == RHSRT->getDecl())
         return lexT;
       
       Diag(questionLoc, diag::err_typecheck_cond_incompatible_operands,
@@ -826,11 +827,19 @@ Action::ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc,
                                             ExprTy *RHS) {
   Expr *CondExpr = (Expr *) Cond;
   Expr *LHSExpr = (Expr *) LHS, *RHSExpr = (Expr *) RHS;
+
+  // If this is the gnu "x ?: y" extension, analyze the types as though the LHS
+  // was the condition.
+  bool isLHSNull = LHSExpr == 0;
+  if (isLHSNull)
+    LHSExpr = CondExpr;
+  
   QualType result = CheckConditionalOperands(CondExpr, LHSExpr, 
                                              RHSExpr, QuestionLoc);
   if (result.isNull())
     return true;
-  return new ConditionalOperator(CondExpr, LHSExpr, RHSExpr, result);
+  return new ConditionalOperator(CondExpr, isLHSNull ? 0 : LHSExpr,
+                                 RHSExpr, result);
 }
 
 /// DefaultArgumentPromotion (C99 6.5.2.2p6). Used for function calls that
diff --git a/test/CodeGen/conditional-gnu-ext.c b/test/CodeGen/conditional-gnu-ext.c
new file mode 100644 (file)
index 0000000..5b2eb3f
--- /dev/null
@@ -0,0 +1,6 @@
+// RUN: clang -emit-llvm %s
+// PR1824
+
+int foo(int x, short y) {
+  return x ?: y;
+}