From: Anders Carlsson Date: Fri, 30 Nov 2007 19:04:31 +0000 (+0000) Subject: GCC has an extension where the left hand side of the ? : operator can be omitted... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=3907323dd6665c0c4e383435cb145233f4533406;p=clang GCC has an extension where the left hand side of the ? : operator can be omitted. Handle this in a few more places. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@44462 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/AST/Expr.cpp b/AST/Expr.cpp index 682b4bd92b..0aee702c65 100644 --- a/AST/Expr.cpp +++ b/AST/Expr.cpp @@ -494,7 +494,8 @@ bool Expr::isConstantExpr(ASTContext &Ctx, SourceLocation *Loc) const { case ConditionalOperatorClass: { const ConditionalOperator *Exp = cast(this); if (!Exp->getCond()->isConstantExpr(Ctx, Loc) || - !Exp->getLHS()->isConstantExpr(Ctx, Loc) || + // Handle the GNU extension for missing LHS. + !(Exp->getLHS() && Exp->getLHS()->isConstantExpr(Ctx, Loc)) || !Exp->getRHS()->isConstantExpr(Ctx, Loc)) return false; return true; @@ -809,10 +810,11 @@ bool Expr::isIntegerConstantExpr(llvm::APSInt &Result, ASTContext &Ctx, if (Result == 0) std::swap(TrueExp, FalseExp); // Evaluate the false one first, discard the result. - if (!FalseExp->isIntegerConstantExpr(Result, Ctx, Loc, false)) + if (FalseExp && !FalseExp->isIntegerConstantExpr(Result, Ctx, Loc, false)) return false; // Evalute the true one, capture the result. - if (!TrueExp->isIntegerConstantExpr(Result, Ctx, Loc, isEvaluated)) + if (TrueExp && + !TrueExp->isIntegerConstantExpr(Result, Ctx, Loc, isEvaluated)) return false; break; } diff --git a/Analysis/UninitializedValues.cpp b/Analysis/UninitializedValues.cpp index 8a27b71b8f..35d6124e62 100644 --- a/Analysis/UninitializedValues.cpp +++ b/Analysis/UninitializedValues.cpp @@ -145,7 +145,13 @@ bool TransferFuncs::VisitUnaryOperator(UnaryOperator* U) { bool TransferFuncs::VisitConditionalOperator(ConditionalOperator* C) { Visit(C->getCond()); - return Visit(C->getLHS()) & Visit(C->getRHS()); // Yes: we want &, not &&. + + bool rhsResult = Visit(C->getRHS()); + // Handle the GNU extension for missing LHS. + if (Expr *lhs = C->getLHS()) + return Visit(lhs) & rhsResult; // Yes: we want &, not &&. + else + return rhsResult; } bool TransferFuncs::VisitStmt(Stmt* S) { diff --git a/Sema/SemaChecking.cpp b/Sema/SemaChecking.cpp index 20f0b81b43..81a18c9645 100644 --- a/Sema/SemaChecking.cpp +++ b/Sema/SemaChecking.cpp @@ -564,10 +564,12 @@ static DeclRefExpr* EvalAddr(Expr *E) { case Stmt::ConditionalOperatorClass: { ConditionalOperator *C = cast(E); - if (DeclRefExpr* LHS = EvalAddr(C->getLHS())) - return LHS; - else - return EvalAddr(C->getRHS()); + // Handle the GNU extension for missing LHS. + if (Expr *lhsExpr = C->getLHS()) + if (DeclRefExpr* LHS = EvalAddr(lhsExpr)) + return LHS; + + return EvalAddr(C->getRHS()); } // For implicit casts, we need to handle conversions from arrays to @@ -674,10 +676,12 @@ static DeclRefExpr* EvalVal(Expr *E) { // non-NULL DeclRefExpr's. If one is non-NULL, we return it. ConditionalOperator *C = cast(E); - if (DeclRefExpr *LHS = EvalVal(C->getLHS())) - return LHS; - else - return EvalVal(C->getRHS()); + // Handle the GNU extension for missing LHS. + if (Expr *lhsExpr = C->getLHS()) + if (DeclRefExpr *LHS = EvalVal(lhsExpr)) + return LHS; + + return EvalVal(C->getRHS()); } // Accesses to members are potential references to data on the stack. diff --git a/test/Analysis/conditional-op-missing-lhs.c b/test/Analysis/conditional-op-missing-lhs.c new file mode 100644 index 0000000000..917212d387 --- /dev/null +++ b/test/Analysis/conditional-op-missing-lhs.c @@ -0,0 +1,26 @@ +// RUN: clang -warn-dead-stores -warn-uninit-values -verify %s + +void f1() +{ + int i; + + int j = i ? : 1; // expected-warning{{use of uninitialized variable}} +} + +void *f2(int *i) +{ + return i ? : 0; +} + +void *f3(int *i) +{ + int a; + + return &a ? : i; +} + +void f4() +{ + char c[1 ? : 2]; +} +