From 2ab40a6207d3a522a81beb300a5cb560eef81299 Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Mon, 26 Nov 2007 01:40:58 +0000 Subject: [PATCH] Fix sema support for the gnu ?: expression with a missing middle expression, and fix a codegen bug where we didn't correctly promote the condition to the right result type. This fixes PR1824. llvm-svn: 44322 --- clang/CodeGen/CGExprScalar.cpp | 16 +++++++++++++--- clang/Sema/SemaExpr.cpp | 15 ++++++++++++--- clang/test/CodeGen/conditional-gnu-ext.c | 6 ++++++ 3 files changed, 31 insertions(+), 6 deletions(-) create mode 100644 clang/test/CodeGen/conditional-gnu-ext.c diff --git a/clang/CodeGen/CGExprScalar.cpp b/clang/CodeGen/CGExprScalar.cpp index 669928b6f07d..f0a75dbf1366 100644 --- a/clang/CodeGen/CGExprScalar.cpp +++ b/clang/CodeGen/CGExprScalar.cpp @@ -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(); diff --git a/clang/Sema/SemaExpr.cpp b/clang/Sema/SemaExpr.cpp index a9cd41580bbb..dcec7253eac0 100644 --- a/clang/Sema/SemaExpr.cpp +++ b/clang/Sema/SemaExpr.cpp @@ -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/clang/test/CodeGen/conditional-gnu-ext.c b/clang/test/CodeGen/conditional-gnu-ext.c new file mode 100644 index 000000000000..5b2eb3f3d5eb --- /dev/null +++ b/clang/test/CodeGen/conditional-gnu-ext.c @@ -0,0 +1,6 @@ +// RUN: clang -emit-llvm %s +// PR1824 + +int foo(int x, short y) { + return x ?: y; +}