aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnders Carlsson <andersca@mac.com>2007-11-30 19:04:31 +0000
committerAnders Carlsson <andersca@mac.com>2007-11-30 19:04:31 +0000
commit3907323dd6665c0c4e383435cb145233f4533406 (patch)
tree14734649e3ede0685322f84ce7c4153fc9ab0746
parentb0ff33a9f4b2a75b6949976bbf3782ff0d839cb1 (diff)
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
-rw-r--r--AST/Expr.cpp8
-rw-r--r--Analysis/UninitializedValues.cpp8
-rw-r--r--Sema/SemaChecking.cpp20
-rw-r--r--test/Analysis/conditional-op-missing-lhs.c26
4 files changed, 50 insertions, 12 deletions
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<ConditionalOperator>(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<ConditionalOperator>(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<ConditionalOperator>(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];
+}
+