C1X: implement generic selections
As an extension, generic selection support has been added for all
supported languages. The syntax is the same as for C1X.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@129554 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 259c39c..1f6c2fa 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -35,18 +35,16 @@
/// but also int expressions which are produced by things like comparisons in
/// C.
bool Expr::isKnownToHaveBooleanValue() const {
+ const Expr *E = IgnoreParens();
+
// If this value has _Bool type, it is obvious 0/1.
- if (getType()->isBooleanType()) return true;
+ if (E->getType()->isBooleanType()) return true;
// If this is a non-scalar-integer type, we don't care enough to try.
- if (!getType()->isIntegralOrEnumerationType()) return false;
+ if (!E->getType()->isIntegralOrEnumerationType()) return false;
- if (const ParenExpr *PE = dyn_cast<ParenExpr>(this))
- return PE->getSubExpr()->isKnownToHaveBooleanValue();
-
- if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(this)) {
+ if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) {
switch (UO->getOpcode()) {
case UO_Plus:
- case UO_Extension:
return UO->getSubExpr()->isKnownToHaveBooleanValue();
default:
return false;
@@ -55,10 +53,10 @@
// Only look through implicit casts. If the user writes
// '(int) (a && b)' treat it as an arbitrary int.
- if (const ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(this))
+ if (const ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(E))
return CE->getSubExpr()->isKnownToHaveBooleanValue();
- if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(this)) {
+ if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
switch (BO->getOpcode()) {
default: return false;
case BO_LT: // Relational operators.
@@ -84,7 +82,7 @@
}
}
- if (const ConditionalOperator *CO = dyn_cast<ConditionalOperator>(this))
+ if (const ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E))
return CO->getTrueExpr()->isKnownToHaveBooleanValue() &&
CO->getFalseExpr()->isKnownToHaveBooleanValue();
@@ -1363,6 +1361,9 @@
case ParenExprClass:
return cast<ParenExpr>(this)->getSubExpr()->
isUnusedResultAWarning(Loc, R1, R2, Ctx);
+ case GenericSelectionExprClass:
+ return cast<GenericSelectionExpr>(this)->getResultExpr()->
+ isUnusedResultAWarning(Loc, R1, R2, Ctx);
case UnaryOperatorClass: {
const UnaryOperator *UO = cast<UnaryOperator>(this);
@@ -1573,21 +1574,20 @@
/// isOBJCGCCandidate - Check if an expression is objc gc'able.
/// returns true, if it is; false otherwise.
bool Expr::isOBJCGCCandidate(ASTContext &Ctx) const {
- switch (getStmtClass()) {
+ const Expr *E = IgnoreParens();
+ switch (E->getStmtClass()) {
default:
return false;
case ObjCIvarRefExprClass:
return true;
case Expr::UnaryOperatorClass:
- return cast<UnaryOperator>(this)->getSubExpr()->isOBJCGCCandidate(Ctx);
- case ParenExprClass:
- return cast<ParenExpr>(this)->getSubExpr()->isOBJCGCCandidate(Ctx);
+ return cast<UnaryOperator>(E)->getSubExpr()->isOBJCGCCandidate(Ctx);
case ImplicitCastExprClass:
- return cast<ImplicitCastExpr>(this)->getSubExpr()->isOBJCGCCandidate(Ctx);
+ return cast<ImplicitCastExpr>(E)->getSubExpr()->isOBJCGCCandidate(Ctx);
case CStyleCastExprClass:
- return cast<CStyleCastExpr>(this)->getSubExpr()->isOBJCGCCandidate(Ctx);
+ return cast<CStyleCastExpr>(E)->getSubExpr()->isOBJCGCCandidate(Ctx);
case DeclRefExprClass: {
- const Decl *D = cast<DeclRefExpr>(this)->getDecl();
+ const Decl *D = cast<DeclRefExpr>(E)->getDecl();
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
if (VD->hasGlobalStorage())
return true;
@@ -1600,11 +1600,11 @@
return false;
}
case MemberExprClass: {
- const MemberExpr *M = cast<MemberExpr>(this);
+ const MemberExpr *M = cast<MemberExpr>(E);
return M->getBase()->isOBJCGCCandidate(Ctx);
}
case ArraySubscriptExprClass:
- return cast<ArraySubscriptExpr>(this)->getBase()->isOBJCGCCandidate(Ctx);
+ return cast<ArraySubscriptExpr>(E)->getBase()->isOBJCGCCandidate(Ctx);
}
}
@@ -1827,6 +1827,11 @@
return CT_Dependent;
return cast<ChooseExpr>(this)->getChosenSubExpr(C)->CanThrow(C);
+ case GenericSelectionExprClass:
+ if (cast<GenericSelectionExpr>(this)->isResultDependent())
+ return CT_Dependent;
+ return cast<GenericSelectionExpr>(this)->getResultExpr()->CanThrow(C);
+
// Some expressions are always dependent.
case DependentScopeDeclRefExprClass:
case CXXUnresolvedConstructExprClass:
@@ -1853,6 +1858,12 @@
continue;
}
}
+ if (GenericSelectionExpr* P = dyn_cast<GenericSelectionExpr>(E)) {
+ if (!P->isResultDependent()) {
+ E = P->getResultExpr();
+ continue;
+ }
+ }
return E;
}
}
@@ -1876,6 +1887,12 @@
continue;
}
}
+ if (GenericSelectionExpr* P = dyn_cast<GenericSelectionExpr>(E)) {
+ if (!P->isResultDependent()) {
+ E = P->getResultExpr();
+ continue;
+ }
+ }
return E;
}
}
@@ -1900,6 +1917,11 @@
E = P->getSubExpr();
continue;
}
+ } else if (GenericSelectionExpr* P = dyn_cast<GenericSelectionExpr>(E)) {
+ if (!P->isResultDependent()) {
+ E = P->getResultExpr();
+ continue;
+ }
}
break;
}
@@ -1923,6 +1945,12 @@
continue;
}
}
+ if (GenericSelectionExpr* P = dyn_cast<GenericSelectionExpr>(E)) {
+ if (!P->isResultDependent()) {
+ E = P->getResultExpr();
+ continue;
+ }
+ }
return E;
}
}
@@ -1965,6 +1993,13 @@
}
}
+ if (GenericSelectionExpr* P = dyn_cast<GenericSelectionExpr>(E)) {
+ if (!P->isResultDependent()) {
+ E = P->getResultExpr();
+ continue;
+ }
+ }
+
return E;
}
}
@@ -2156,6 +2191,11 @@
case ParenExprClass:
return cast<ParenExpr>(this)->getSubExpr()
->isConstantInitializer(Ctx, IsForRef);
+ case GenericSelectionExprClass:
+ if (cast<GenericSelectionExpr>(this)->isResultDependent())
+ return false;
+ return cast<GenericSelectionExpr>(this)->getResultExpr()
+ ->isConstantInitializer(Ctx, IsForRef);
case ChooseExprClass:
return cast<ChooseExpr>(this)->getChosenSubExpr(Ctx)
->isConstantInitializer(Ctx, IsForRef);
@@ -2242,6 +2282,9 @@
// Accept ((void*)0) as a null pointer constant, as many other
// implementations do.
return PE->getSubExpr()->isNullPointerConstant(Ctx, NPC);
+ } else if (const GenericSelectionExpr *GE =
+ dyn_cast<GenericSelectionExpr>(this)) {
+ return GE->getResultExpr()->isNullPointerConstant(Ctx, NPC);
} else if (const CXXDefaultArgExpr *DefaultArg
= dyn_cast<CXXDefaultArgExpr>(this)) {
// See through default argument expressions
@@ -2640,6 +2683,51 @@
memcpy(SubExprs, Exprs, sizeof(Expr *) * NumExprs);
}
+GenericSelectionExpr::GenericSelectionExpr(ASTContext &Context,
+ SourceLocation GenericLoc, Expr *ControllingExpr,
+ TypeSourceInfo **AssocTypes, Expr **AssocExprs,
+ unsigned NumAssocs, SourceLocation DefaultLoc,
+ SourceLocation RParenLoc,
+ bool ContainsUnexpandedParameterPack,
+ unsigned ResultIndex)
+ : Expr(GenericSelectionExprClass,
+ AssocExprs[ResultIndex]->getType(),
+ AssocExprs[ResultIndex]->getValueKind(),
+ AssocExprs[ResultIndex]->getObjectKind(),
+ AssocExprs[ResultIndex]->isTypeDependent(),
+ AssocExprs[ResultIndex]->isValueDependent(),
+ ContainsUnexpandedParameterPack),
+ AssocTypes(new (Context) TypeSourceInfo*[NumAssocs]),
+ SubExprs(new (Context) Stmt*[END_EXPR+NumAssocs]), NumAssocs(NumAssocs),
+ ResultIndex(ResultIndex), GenericLoc(GenericLoc), DefaultLoc(DefaultLoc),
+ RParenLoc(RParenLoc) {
+ SubExprs[CONTROLLING] = ControllingExpr;
+ std::copy(AssocTypes, AssocTypes+NumAssocs, this->AssocTypes);
+ std::copy(AssocExprs, AssocExprs+NumAssocs, SubExprs+END_EXPR);
+}
+
+GenericSelectionExpr::GenericSelectionExpr(ASTContext &Context,
+ SourceLocation GenericLoc, Expr *ControllingExpr,
+ TypeSourceInfo **AssocTypes, Expr **AssocExprs,
+ unsigned NumAssocs, SourceLocation DefaultLoc,
+ SourceLocation RParenLoc,
+ bool ContainsUnexpandedParameterPack)
+ : Expr(GenericSelectionExprClass,
+ Context.DependentTy,
+ VK_RValue,
+ OK_Ordinary,
+ /*isTypeDependent=*/ true,
+ /*isValueDependent=*/ true,
+ ContainsUnexpandedParameterPack),
+ AssocTypes(new (Context) TypeSourceInfo*[NumAssocs]),
+ SubExprs(new (Context) Stmt*[END_EXPR+NumAssocs]), NumAssocs(NumAssocs),
+ ResultIndex(-1U), GenericLoc(GenericLoc), DefaultLoc(DefaultLoc),
+ RParenLoc(RParenLoc) {
+ SubExprs[CONTROLLING] = ControllingExpr;
+ std::copy(AssocTypes, AssocTypes+NumAssocs, this->AssocTypes);
+ std::copy(AssocExprs, AssocExprs+NumAssocs, SubExprs+END_EXPR);
+}
+
//===----------------------------------------------------------------------===//
// DesignatedInitExpr
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp
index e94ae82..803bc56 100644
--- a/lib/AST/ExprClassification.cpp
+++ b/lib/AST/ExprClassification.cpp
@@ -233,6 +233,14 @@
case Expr::ParenExprClass:
return ClassifyInternal(Ctx, cast<ParenExpr>(E)->getSubExpr());
+ // C1X 6.5.1.1p4: [A generic selection] is an lvalue, a function designator,
+ // or a void expression if its result expression is, respectively, an
+ // lvalue, a function designator, or a void expression.
+ case Expr::GenericSelectionExprClass:
+ if (cast<GenericSelectionExpr>(E)->isResultDependent())
+ return Cl::CL_PRValue;
+ return ClassifyInternal(Ctx,cast<GenericSelectionExpr>(E)->getResultExpr());
+
case Expr::BinaryOperatorClass:
case Expr::CompoundAssignOperatorClass:
// C doesn't have any binary expressions that are lvalues.
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index cdd7efa..0ec122d 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -274,6 +274,9 @@
}
bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
+ bool VisitGenericSelectionExpr(GenericSelectionExpr *E) {
+ return Visit(E->getResultExpr());
+ }
bool VisitDeclRefExpr(DeclRefExpr *E) {
if (Info.Ctx.getCanonicalType(E->getType()).isVolatileQualified())
return true;
@@ -372,6 +375,9 @@
}
bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
+ bool VisitGenericSelectionExpr(GenericSelectionExpr *E) {
+ return Visit(E->getResultExpr());
+ }
bool VisitDeclRefExpr(DeclRefExpr *E);
bool VisitPredefinedExpr(PredefinedExpr *E) { return Success(E); }
bool VisitCompoundLiteralExpr(CompoundLiteralExpr *E);
@@ -501,6 +507,9 @@
}
bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
+ bool VisitGenericSelectionExpr(GenericSelectionExpr *E) {
+ return Visit(E->getResultExpr());
+ }
bool VisitBinaryOperator(const BinaryOperator *E);
bool VisitCastExpr(CastExpr* E);
@@ -717,6 +726,8 @@
APValue VisitParenExpr(ParenExpr *E)
{ return Visit(E->getSubExpr()); }
+ APValue VisitGenericSelectionExpr(GenericSelectionExpr *E)
+ { return Visit(E->getResultExpr()); }
APValue VisitUnaryExtension(const UnaryOperator *E)
{ return Visit(E->getSubExpr()); }
APValue VisitUnaryPlus(const UnaryOperator *E)
@@ -975,6 +986,9 @@
}
bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
+ bool VisitGenericSelectionExpr(GenericSelectionExpr *E) {
+ return Visit(E->getResultExpr());
+ }
bool VisitIntegerLiteral(const IntegerLiteral *E) {
return Success(E->getValue(), E);
@@ -1918,6 +1932,9 @@
}
bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
+ bool VisitGenericSelectionExpr(GenericSelectionExpr *E) {
+ return Visit(E->getResultExpr());
+ }
bool VisitCallExpr(const CallExpr *E);
bool VisitUnaryOperator(const UnaryOperator *E);
@@ -2251,6 +2268,9 @@
}
bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
+ bool VisitGenericSelectionExpr(GenericSelectionExpr *E) {
+ return Visit(E->getResultExpr());
+ }
bool VisitImaginaryLiteral(ImaginaryLiteral *E);
@@ -2839,6 +2859,8 @@
case Expr::ParenExprClass:
return CheckICE(cast<ParenExpr>(E)->getSubExpr(), Ctx);
+ case Expr::GenericSelectionExprClass:
+ return CheckICE(cast<GenericSelectionExpr>(E)->getResultExpr(), Ctx);
case Expr::IntegerLiteralClass:
case Expr::CharacterLiteralClass:
case Expr::CXXBoolLiteralExprClass:
diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp
index be17ccf..752163a 100644
--- a/lib/AST/ItaniumMangle.cpp
+++ b/lib/AST/ItaniumMangle.cpp
@@ -1750,6 +1750,7 @@
case Expr::ChooseExprClass:
case Expr::CompoundLiteralExprClass:
case Expr::ExtVectorElementExprClass:
+ case Expr::GenericSelectionExprClass:
case Expr::ObjCEncodeExprClass:
case Expr::ObjCIsaExprClass:
case Expr::ObjCIvarRefExprClass:
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index 37010a0..8963126 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -737,6 +737,23 @@
PrintExpr(Node->getArgumentExpr());
}
}
+
+void StmtPrinter::VisitGenericSelectionExpr(GenericSelectionExpr *Node) {
+ OS << "_Generic(";
+ PrintExpr(Node->getControllingExpr());
+ for (unsigned i = 0; i != Node->getNumAssocs(); ++i) {
+ OS << ", ";
+ QualType T = Node->getAssocType(i);
+ if (T.isNull())
+ OS << "default";
+ else
+ OS << T.getAsString(Policy);
+ OS << ": ";
+ PrintExpr(Node->getAssocExpr(i));
+ }
+ OS << ")";
+}
+
void StmtPrinter::VisitArraySubscriptExpr(ArraySubscriptExpr *Node) {
PrintExpr(Node->getLHS());
OS << "[";
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index 92292ce..dbcb7e4 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -434,6 +434,18 @@
ID.AddBoolean(S->isConstQualAdded());
}
+void StmtProfiler::VisitGenericSelectionExpr(GenericSelectionExpr *S) {
+ VisitExpr(S);
+ for (unsigned i = 0; i != S->getNumAssocs(); ++i) {
+ QualType T = S->getAssocType(i);
+ if (T.isNull())
+ ID.AddPointer(0);
+ else
+ VisitType(T);
+ VisitExpr(S->getAssocExpr(i));
+ }
+}
+
static Stmt::StmtClass DecodeOperatorCall(CXXOperatorCallExpr *S,
UnaryOperatorKind &UnaryOp,
BinaryOperatorKind &BinaryOp) {
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index 92e6a19..e0935ac 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -239,10 +239,7 @@
llvm::SmallVector<SubobjectAdjustment, 2> Adjustments;
while (true) {
- if (const ParenExpr *PE = dyn_cast<ParenExpr>(E)) {
- E = PE->getSubExpr();
- continue;
- }
+ E = E->IgnoreParens();
if (const CastExpr *CE = dyn_cast<CastExpr>(E)) {
if ((CE->getCastKind() == CK_DerivedToBase ||
@@ -545,6 +542,8 @@
case Expr::DeclRefExprClass:
return EmitDeclRefLValue(cast<DeclRefExpr>(E));
case Expr::ParenExprClass:return EmitLValue(cast<ParenExpr>(E)->getSubExpr());
+ case Expr::GenericSelectionExprClass:
+ return EmitLValue(cast<GenericSelectionExpr>(E)->getResultExpr());
case Expr::PredefinedExprClass:
return EmitPredefinedLValue(cast<PredefinedExpr>(E));
case Expr::StringLiteralClass:
@@ -1099,6 +1098,12 @@
}
return;
}
+
+ if (const GenericSelectionExpr *Exp = dyn_cast<GenericSelectionExpr>(E)) {
+ setObjCGCLValueClass(Ctx, Exp->getResultExpr(), LV);
+ return;
+ }
+
if (const ImplicitCastExpr *Exp = dyn_cast<ImplicitCastExpr>(E)) {
setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV);
return;
diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp
index 4315915..6fb9987 100644
--- a/lib/CodeGen/CGExprAgg.cpp
+++ b/lib/CodeGen/CGExprAgg.cpp
@@ -81,6 +81,9 @@
CGF.ErrorUnsupported(S, "aggregate expression");
}
void VisitParenExpr(ParenExpr *PE) { Visit(PE->getSubExpr()); }
+ void VisitGenericSelectionExpr(GenericSelectionExpr *GE) {
+ Visit(GE->getResultExpr());
+ }
void VisitUnaryExtension(UnaryOperator *E) { Visit(E->getSubExpr()); }
// l-values.
@@ -518,9 +521,8 @@
/// zero to memory, return true. This can return false if uncertain, so it just
/// handles simple cases.
static bool isSimpleZero(const Expr *E, CodeGenFunction &CGF) {
- // (0)
- if (const ParenExpr *PE = dyn_cast<ParenExpr>(E))
- return isSimpleZero(PE->getSubExpr(), CGF);
+ E = E->IgnoreParens();
+
// 0
if (const IntegerLiteral *IL = dyn_cast<IntegerLiteral>(E))
return IL->getValue() == 0;
@@ -743,8 +745,7 @@
/// non-zero bytes that will be stored when outputting the initializer for the
/// specified initializer expression.
static uint64_t GetNumNonZeroBytesInInit(const Expr *E, CodeGenFunction &CGF) {
- if (const ParenExpr *PE = dyn_cast<ParenExpr>(E))
- return GetNumNonZeroBytesInInit(PE->getSubExpr(), CGF);
+ E = E->IgnoreParens();
// 0 and 0.0 won't require any non-zero stores!
if (isSimpleZero(E, CGF)) return 0;
diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp
index f4af6a5..bd19586 100644
--- a/lib/CodeGen/CGExprComplex.cpp
+++ b/lib/CodeGen/CGExprComplex.cpp
@@ -108,6 +108,9 @@
}
ComplexPairTy VisitExpr(Expr *S);
ComplexPairTy VisitParenExpr(ParenExpr *PE) { return Visit(PE->getSubExpr());}
+ ComplexPairTy VisitGenericSelectionExpr(GenericSelectionExpr *GE) {
+ return Visit(GE->getResultExpr());
+ }
ComplexPairTy VisitImaginaryLiteral(const ImaginaryLiteral *IL);
// l-values.
diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp
index 3a2fb9b..8e26b20 100644
--- a/lib/CodeGen/CGExprConstant.cpp
+++ b/lib/CodeGen/CGExprConstant.cpp
@@ -457,6 +457,10 @@
return Visit(PE->getSubExpr());
}
+ llvm::Constant *VisitGenericSelectionExpr(GenericSelectionExpr *GE) {
+ return Visit(GE->getResultExpr());
+ }
+
llvm::Constant *VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
return Visit(E->getInitializer());
}
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index a44c03e..556dbf5 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -163,6 +163,9 @@
Value *VisitParenExpr(ParenExpr *PE) {
return Visit(PE->getSubExpr());
}
+ Value *VisitGenericSelectionExpr(GenericSelectionExpr *GE) {
+ return Visit(GE->getResultExpr());
+ }
// Leaves.
Value *VisitIntegerLiteral(const IntegerLiteral *E) {
@@ -2396,8 +2399,7 @@
/// flow into selects in some cases.
static bool isCheapEnoughToEvaluateUnconditionally(const Expr *E,
CodeGenFunction &CGF) {
- if (const ParenExpr *PE = dyn_cast<ParenExpr>(E))
- return isCheapEnoughToEvaluateUnconditionally(PE->getSubExpr(), CGF);
+ E = E->IgnoreParens();
// TODO: Allow anything we can constant fold to an integer or fp constant.
if (isa<IntegerLiteral>(E) || isa<CharacterLiteral>(E) ||
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index 7a59efe..e10e285 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -469,8 +469,7 @@
void CodeGenFunction::EmitBranchOnBoolExpr(const Expr *Cond,
llvm::BasicBlock *TrueBlock,
llvm::BasicBlock *FalseBlock) {
- if (const ParenExpr *PE = dyn_cast<ParenExpr>(Cond))
- return EmitBranchOnBoolExpr(PE->getSubExpr(), TrueBlock, FalseBlock);
+ Cond = Cond->IgnoreParens();
if (const BinaryOperator *CondBOp = dyn_cast<BinaryOperator>(Cond)) {
// Handle X && Y in a condition.
diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp
index 71f3327..6e9f598 100644
--- a/lib/Lex/PPMacroExpansion.cpp
+++ b/lib/Lex/PPMacroExpansion.cpp
@@ -548,6 +548,7 @@
.Case("cxx_exceptions", LangOpts.Exceptions)
.Case("cxx_rtti", LangOpts.RTTI)
.Case("enumerator_attributes", true)
+ .Case("generic_selections", true)
.Case("objc_nonfragile_abi", LangOpts.ObjCNonFragileABI)
.Case("objc_weak_class", LangOpts.ObjCNonFragileABI)
.Case("ownership_holds", true)
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index d8d73e9..cf852f8 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -465,6 +465,7 @@
/// [C++] boolean-literal [C++ 2.13.5]
/// [C++0x] 'nullptr' [C++0x 2.14.7]
/// '(' expression ')'
+/// [C1X] generic-selection
/// '__func__' [C99 6.4.2.2]
/// [GNU] '__FUNCTION__'
/// [GNU] '__PRETTY_FUNCTION__'
@@ -731,6 +732,9 @@
case tok::wide_string_literal:
Res = ParseStringLiteralExpression();
break;
+ case tok::kw__Generic: // primary-expression: generic-selection [C1X 6.5.1]
+ Res = ParseGenericSelectionExpression();
+ break;
case tok::kw___builtin_va_arg:
case tok::kw___builtin_offsetof:
case tok::kw___builtin_choose_expr:
@@ -1802,6 +1806,100 @@
return Actions.ActOnStringLiteral(&StringToks[0], StringToks.size());
}
+/// ParseGenericSelectionExpression - Parse a C1X generic-selection
+/// [C1X 6.5.1.1].
+///
+/// generic-selection:
+/// _Generic ( assignment-expression , generic-assoc-list )
+/// generic-assoc-list:
+/// generic-association
+/// generic-assoc-list , generic-association
+/// generic-association:
+/// type-name : assignment-expression
+/// default : assignment-expression
+ExprResult Parser::ParseGenericSelectionExpression() {
+ assert(Tok.is(tok::kw__Generic) && "_Generic keyword expected");
+ SourceLocation KeyLoc = ConsumeToken();
+
+ if (!getLang().C1X)
+ Diag(KeyLoc, diag::ext_c1x_generic_selection);
+
+ SourceLocation LParenLoc = Tok.getLocation();
+ if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen, ""))
+ return ExprError();
+
+ ExprResult ControllingExpr;
+ {
+ // C1X 6.5.1.1p3 "The controlling expression of a generic selection is
+ // not evaluated."
+ EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated);
+ ControllingExpr = ParseAssignmentExpression();
+ if (ControllingExpr.isInvalid()) {
+ SkipUntil(tok::r_paren);
+ return ExprError();
+ }
+ }
+
+ if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "")) {
+ SkipUntil(tok::r_paren);
+ return ExprError();
+ }
+
+ SourceLocation DefaultLoc;
+ TypeVector Types(Actions);
+ ExprVector Exprs(Actions);
+ while (1) {
+ ParsedType Ty;
+ if (Tok.is(tok::kw_default)) {
+ // C1X 6.5.1.1p2 "A generic selection shall have no more than one default
+ // generic association."
+ if (!DefaultLoc.isInvalid()) {
+ Diag(Tok, diag::err_duplicate_default_assoc);
+ Diag(DefaultLoc, diag::note_previous_default_assoc);
+ SkipUntil(tok::r_paren);
+ return ExprError();
+ }
+ DefaultLoc = ConsumeToken();
+ Ty = ParsedType();
+ } else {
+ ColonProtectionRAIIObject X(*this);
+ TypeResult TR = ParseTypeName();
+ if (TR.isInvalid()) {
+ SkipUntil(tok::r_paren);
+ return ExprError();
+ }
+ Ty = TR.release();
+ }
+ Types.push_back(Ty);
+
+ if (ExpectAndConsume(tok::colon, diag::err_expected_colon, "")) {
+ SkipUntil(tok::r_paren);
+ return ExprError();
+ }
+
+ // FIXME: These expressions should be parsed in a potentially potentially
+ // evaluated context.
+ ExprResult ER(ParseAssignmentExpression());
+ if (ER.isInvalid()) {
+ SkipUntil(tok::r_paren);
+ return ExprError();
+ }
+ Exprs.push_back(ER.release());
+
+ if (Tok.isNot(tok::comma))
+ break;
+ ConsumeToken();
+ }
+
+ SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+ if (RParenLoc.isInvalid())
+ return ExprError();
+
+ return Actions.ActOnGenericSelectionExpr(KeyLoc, DefaultLoc, RParenLoc,
+ ControllingExpr.release(),
+ move_arg(Types), move_arg(Exprs));
+}
+
/// ParseExpressionList - Used for C/C++ (argument-)expression-list.
///
/// argument-expression-list:
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 9372a16..cc4a089 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -905,6 +905,8 @@
if (E->isTypeDependent() || E->isValueDependent())
return false;
+ E = E->IgnoreParens();
+
switch (E->getStmtClass()) {
case Stmt::BinaryConditionalOperatorClass:
case Stmt::ConditionalOperatorClass: {
@@ -927,11 +929,6 @@
goto tryAgain;
}
- case Stmt::ParenExprClass: {
- E = cast<ParenExpr>(E)->getSubExpr();
- goto tryAgain;
- }
-
case Stmt::OpaqueValueExprClass:
if (const Expr *src = cast<OpaqueValueExpr>(E)->getSourceExpr()) {
E = src;
@@ -1897,14 +1894,12 @@
E->getType()->isObjCQualifiedIdType()) &&
"EvalAddr only works on pointers");
+ E = E->IgnoreParens();
+
// Our "symbolic interpreter" is just a dispatch off the currently
// viewed AST node. We then recursively traverse the AST by calling
// EvalAddr and EvalVal appropriately.
switch (E->getStmtClass()) {
- case Stmt::ParenExprClass:
- // Ignore parentheses.
- return EvalAddr(cast<ParenExpr>(E)->getSubExpr(), refVars);
-
case Stmt::DeclRefExprClass: {
DeclRefExpr *DR = cast<DeclRefExpr>(E);
@@ -2034,6 +2029,8 @@
// Our "symbolic interpreter" is just a dispatch off the currently
// viewed AST node. We then recursively traverse the AST by calling
// EvalAddr and EvalVal appropriately.
+
+ E = E->IgnoreParens();
switch (E->getStmtClass()) {
case Stmt::ImplicitCastExprClass: {
ImplicitCastExpr *IE = cast<ImplicitCastExpr>(E);
@@ -2067,12 +2064,6 @@
return NULL;
}
- case Stmt::ParenExprClass: {
- // Ignore parentheses.
- E = cast<ParenExpr>(E)->getSubExpr();
- continue;
- }
-
case Stmt::UnaryOperatorClass: {
// The only unary operator that make sense to handle here
// is Deref. All others don't resolve to a "name." This includes
@@ -3272,11 +3263,9 @@
}
void Sema::CheckArrayAccess(const Expr *expr) {
- while (true)
+ while (true) {
+ expr = expr->IgnoreParens();
switch (expr->getStmtClass()) {
- case Stmt::ParenExprClass:
- expr = cast<ParenExpr>(expr)->getSubExpr();
- continue;
case Stmt::ArraySubscriptExprClass:
CheckArrayAccess_Check(*this, cast<ArraySubscriptExpr>(expr));
return;
@@ -3291,4 +3280,5 @@
default:
return;
}
+ }
}
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index b3aaaa2..73825ba 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -748,6 +748,163 @@
//===----------------------------------------------------------------------===//
+ExprResult
+Sema::ActOnGenericSelectionExpr(SourceLocation KeyLoc,
+ SourceLocation DefaultLoc,
+ SourceLocation RParenLoc,
+ Expr *ControllingExpr,
+ MultiTypeArg types,
+ MultiExprArg exprs) {
+ unsigned NumAssocs = types.size();
+ assert(NumAssocs == exprs.size());
+
+ ParsedType *ParsedTypes = types.release();
+ Expr **Exprs = exprs.release();
+
+ TypeSourceInfo **Types = new TypeSourceInfo*[NumAssocs];
+ for (unsigned i = 0; i < NumAssocs; ++i) {
+ if (ParsedTypes[i])
+ (void) GetTypeFromParser(ParsedTypes[i], &Types[i]);
+ else
+ Types[i] = 0;
+ }
+
+ ExprResult ER = CreateGenericSelectionExpr(KeyLoc, DefaultLoc, RParenLoc,
+ ControllingExpr, Types, Exprs,
+ NumAssocs);
+ delete Types;
+ return ER;
+}
+
+ExprResult
+Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc,
+ SourceLocation DefaultLoc,
+ SourceLocation RParenLoc,
+ Expr *ControllingExpr,
+ TypeSourceInfo **Types,
+ Expr **Exprs,
+ unsigned NumAssocs) {
+ bool TypeErrorFound = false,
+ IsResultDependent = ControllingExpr->isTypeDependent(),
+ ContainsUnexpandedParameterPack
+ = ControllingExpr->containsUnexpandedParameterPack();
+
+ for (unsigned i = 0; i < NumAssocs; ++i) {
+ if (Exprs[i]->containsUnexpandedParameterPack())
+ ContainsUnexpandedParameterPack = true;
+
+ if (Types[i]) {
+ if (Types[i]->getType()->containsUnexpandedParameterPack())
+ ContainsUnexpandedParameterPack = true;
+
+ if (Types[i]->getType()->isDependentType()) {
+ IsResultDependent = true;
+ } else {
+ // C1X 6.5.1.1p2 "The type name in a generic association shall specify a
+ // complete object type other than a variably modified type."
+ unsigned D = 0;
+ if (Types[i]->getType()->isIncompleteType())
+ D = diag::err_assoc_type_incomplete;
+ else if (!Types[i]->getType()->isObjectType())
+ D = diag::err_assoc_type_nonobject;
+ else if (Types[i]->getType()->isVariablyModifiedType())
+ D = diag::err_assoc_type_variably_modified;
+
+ if (D != 0) {
+ Diag(Types[i]->getTypeLoc().getBeginLoc(), D)
+ << Types[i]->getTypeLoc().getSourceRange()
+ << Types[i]->getType();
+ TypeErrorFound = true;
+ }
+
+ // C1X 6.5.1.1p2 "No two generic associations in the same generic
+ // selection shall specify compatible types."
+ for (unsigned j = i+1; j < NumAssocs; ++j)
+ if (Types[j] && !Types[j]->getType()->isDependentType() &&
+ Context.typesAreCompatible(Types[i]->getType(),
+ Types[j]->getType())) {
+ Diag(Types[j]->getTypeLoc().getBeginLoc(),
+ diag::err_assoc_compatible_types)
+ << Types[j]->getTypeLoc().getSourceRange()
+ << Types[j]->getType()
+ << Types[i]->getType();
+ Diag(Types[i]->getTypeLoc().getBeginLoc(),
+ diag::note_compat_assoc)
+ << Types[i]->getTypeLoc().getSourceRange()
+ << Types[i]->getType();
+ TypeErrorFound = true;
+ }
+ }
+ }
+ }
+ if (TypeErrorFound)
+ return ExprError();
+
+ // If we determined that the generic selection is result-dependent, don't
+ // try to compute the result expression.
+ if (IsResultDependent)
+ return Owned(new (Context) GenericSelectionExpr(
+ Context, KeyLoc, ControllingExpr,
+ Types, Exprs, NumAssocs, DefaultLoc,
+ RParenLoc, ContainsUnexpandedParameterPack));
+
+ llvm::SmallVector<unsigned, 1> CompatIndices;
+ unsigned DefaultIndex = -1U;
+ for (unsigned i = 0; i < NumAssocs; ++i) {
+ if (!Types[i])
+ DefaultIndex = i;
+ else if (Context.typesAreCompatible(ControllingExpr->getType(),
+ Types[i]->getType()))
+ CompatIndices.push_back(i);
+ }
+
+ // C1X 6.5.1.1p2 "The controlling expression of a generic selection shall have
+ // type compatible with at most one of the types named in its generic
+ // association list."
+ if (CompatIndices.size() > 1) {
+ // We strip parens here because the controlling expression is typically
+ // parenthesized in macro definitions.
+ ControllingExpr = ControllingExpr->IgnoreParens();
+ Diag(ControllingExpr->getLocStart(), diag::err_generic_sel_multi_match)
+ << ControllingExpr->getSourceRange() << ControllingExpr->getType()
+ << (unsigned) CompatIndices.size();
+ for (llvm::SmallVector<unsigned, 1>::iterator I = CompatIndices.begin(),
+ E = CompatIndices.end(); I != E; ++I) {
+ Diag(Types[*I]->getTypeLoc().getBeginLoc(),
+ diag::note_compat_assoc)
+ << Types[*I]->getTypeLoc().getSourceRange()
+ << Types[*I]->getType();
+ }
+ return ExprError();
+ }
+
+ // C1X 6.5.1.1p2 "If a generic selection has no default generic association,
+ // its controlling expression shall have type compatible with exactly one of
+ // the types named in its generic association list."
+ if (DefaultIndex == -1U && CompatIndices.size() == 0) {
+ // We strip parens here because the controlling expression is typically
+ // parenthesized in macro definitions.
+ ControllingExpr = ControllingExpr->IgnoreParens();
+ Diag(ControllingExpr->getLocStart(), diag::err_generic_sel_no_match)
+ << ControllingExpr->getSourceRange() << ControllingExpr->getType();
+ return ExprError();
+ }
+
+ // C1X 6.5.1.1p3 "If a generic selection has a generic association with a
+ // type name that is compatible with the type of the controlling expression,
+ // then the result expression of the generic selection is the expression
+ // in that generic association. Otherwise, the result expression of the
+ // generic selection is the expression in the default generic association."
+ unsigned ResultIndex =
+ CompatIndices.size() ? CompatIndices[0] : DefaultIndex;
+
+ return Owned(new (Context) GenericSelectionExpr(
+ Context, KeyLoc, ControllingExpr,
+ Types, Exprs, NumAssocs, DefaultLoc,
+ RParenLoc, ContainsUnexpandedParameterPack,
+ ResultIndex));
+}
+
/// ActOnStringLiteral - The specified tokens were lexed as pasted string
/// fragments (e.g. "foo" "bar" L"baz"). The result string has to handle string
/// concatenation ([C99 5.1.1.2, translation phase #6]), so it may come from
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index b6d38f6..fadcf26 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -1602,6 +1602,22 @@
RParenLoc);
}
+ /// \brief Build a new generic selection expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ ExprResult RebuildGenericSelectionExpr(SourceLocation KeyLoc,
+ SourceLocation DefaultLoc,
+ SourceLocation RParenLoc,
+ Expr *ControllingExpr,
+ TypeSourceInfo **Types,
+ Expr **Exprs,
+ unsigned NumAssocs) {
+ return getSema().CreateGenericSelectionExpr(KeyLoc, DefaultLoc, RParenLoc,
+ ControllingExpr, Types, Exprs,
+ NumAssocs);
+ }
+
/// \brief Build a new overloaded operator call expression.
///
/// By default, performs semantic analysis to build the new expression.
@@ -5525,6 +5541,42 @@
template<typename Derived>
ExprResult
+TreeTransform<Derived>::TransformGenericSelectionExpr(GenericSelectionExpr *E) {
+ ExprResult ControllingExpr =
+ getDerived().TransformExpr(E->getControllingExpr());
+ if (ControllingExpr.isInvalid())
+ return ExprError();
+
+ llvm::SmallVector<Expr *, 4> AssocExprs;
+ llvm::SmallVector<TypeSourceInfo *, 4> AssocTypes;
+ for (unsigned i = 0; i != E->getNumAssocs(); ++i) {
+ TypeSourceInfo *TS = E->getAssocTypeSourceInfo(i);
+ if (TS) {
+ TypeSourceInfo *AssocType = getDerived().TransformType(TS);
+ if (!AssocType)
+ return ExprError();
+ AssocTypes.push_back(AssocType);
+ } else {
+ AssocTypes.push_back(0);
+ }
+
+ ExprResult AssocExpr = getDerived().TransformExpr(E->getAssocExpr(i));
+ if (AssocExpr.isInvalid())
+ return ExprError();
+ AssocExprs.push_back(AssocExpr.release());
+ }
+
+ return getDerived().RebuildGenericSelectionExpr(E->getGenericLoc(),
+ E->getDefaultLoc(),
+ E->getRParenLoc(),
+ ControllingExpr.release(),
+ AssocTypes.data(),
+ AssocExprs.data(),
+ E->getNumAssocs());
+}
+
+template<typename Derived>
+ExprResult
TreeTransform<Derived>::TransformParenExpr(ParenExpr *E) {
ExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr());
if (SubExpr.isInvalid())
diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp
index 68591be..79b0e48 100644
--- a/lib/Serialization/ASTReaderStmt.cpp
+++ b/lib/Serialization/ASTReaderStmt.cpp
@@ -122,6 +122,7 @@
void VisitShuffleVectorExpr(ShuffleVectorExpr *E);
void VisitBlockExpr(BlockExpr *E);
void VisitBlockDeclRefExpr(BlockDeclRefExpr *E);
+ void VisitGenericSelectionExpr(GenericSelectionExpr *E);
void VisitObjCStringLiteral(ObjCStringLiteral *E);
void VisitObjCEncodeExpr(ObjCEncodeExpr *E);
void VisitObjCSelectorExpr(ObjCSelectorExpr *E);
@@ -822,6 +823,25 @@
E->setConstQualAdded(Record[Idx++]);
}
+void ASTStmtReader::VisitGenericSelectionExpr(GenericSelectionExpr *E) {
+ VisitExpr(E);
+ E->NumAssocs = Record[Idx++];
+ E->AssocTypes = new (*Reader.getContext()) TypeSourceInfo*[E->NumAssocs];
+ E->SubExprs =
+ new(*Reader.getContext()) Stmt*[GenericSelectionExpr::END_EXPR+E->NumAssocs];
+
+ E->SubExprs[GenericSelectionExpr::CONTROLLING] = Reader.ReadSubExpr();
+ for (unsigned I = 0, N = E->getNumAssocs(); I != N; ++I) {
+ E->AssocTypes[I] = GetTypeSourceInfo(Record, Idx);
+ E->SubExprs[GenericSelectionExpr::END_EXPR+I] = Reader.ReadSubExpr();
+ }
+ E->ResultIndex = Record[Idx++];
+
+ E->GenericLoc = ReadSourceLocation(Record, Idx);
+ E->DefaultLoc = ReadSourceLocation(Record, Idx);
+ E->RParenLoc = ReadSourceLocation(Record, Idx);
+}
+
//===----------------------------------------------------------------------===//
// Objective-C Expressions and Statements
@@ -1696,6 +1716,10 @@
S = new (Context) BlockDeclRefExpr(Empty);
break;
+ case EXPR_GENERIC_SELECTION:
+ S = new (Context) GenericSelectionExpr(Empty);
+ break;
+
case EXPR_OBJC_STRING_LITERAL:
S = new (Context) ObjCStringLiteral(Empty);
break;
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index d6a9a95..279467a 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -659,6 +659,7 @@
RECORD(EXPR_SHUFFLE_VECTOR);
RECORD(EXPR_BLOCK);
RECORD(EXPR_BLOCK_DECL_REF);
+ RECORD(EXPR_GENERIC_SELECTION);
RECORD(EXPR_OBJC_STRING_LITERAL);
RECORD(EXPR_OBJC_ENCODE);
RECORD(EXPR_OBJC_SELECTOR_EXPR);
diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp
index 9d54bb9..64c2d56 100644
--- a/lib/Serialization/ASTWriterStmt.cpp
+++ b/lib/Serialization/ASTWriterStmt.cpp
@@ -93,6 +93,7 @@
void VisitShuffleVectorExpr(ShuffleVectorExpr *E);
void VisitBlockExpr(BlockExpr *E);
void VisitBlockDeclRefExpr(BlockDeclRefExpr *E);
+ void VisitGenericSelectionExpr(GenericSelectionExpr *E);
// Objective-C Expressions
void VisitObjCStringLiteral(ObjCStringLiteral *E);
@@ -785,6 +786,23 @@
Code = serialization::EXPR_BLOCK_DECL_REF;
}
+void ASTStmtWriter::VisitGenericSelectionExpr(GenericSelectionExpr *E) {
+ VisitExpr(E);
+ Record.push_back(E->getNumAssocs());
+
+ Writer.AddStmt(E->getControllingExpr());
+ for (unsigned I = 0, N = E->getNumAssocs(); I != N; ++I) {
+ Writer.AddTypeSourceInfo(E->getAssocTypeSourceInfo(I), Record);
+ Writer.AddStmt(E->getAssocExpr(I));
+ }
+ Record.push_back(E->isResultDependent() ? -1U : E->getResultIndex());
+
+ Writer.AddSourceLocation(E->getGenericLoc(), Record);
+ Writer.AddSourceLocation(E->getDefaultLoc(), Record);
+ Writer.AddSourceLocation(E->getRParenLoc(), Record);
+ Code = serialization::EXPR_GENERIC_SELECTION;
+}
+
//===----------------------------------------------------------------------===//
// Objective-C Expressions and Statements.
//===----------------------------------------------------------------------===//
diff --git a/lib/StaticAnalyzer/Core/BugReporter.cpp b/lib/StaticAnalyzer/Core/BugReporter.cpp
index 74cd359..26a89c3 100644
--- a/lib/StaticAnalyzer/Core/BugReporter.cpp
+++ b/lib/StaticAnalyzer/Core/BugReporter.cpp
@@ -859,7 +859,8 @@
default:
break;
case Stmt::ParenExprClass:
- S = cast<ParenExpr>(S)->IgnoreParens();
+ case Stmt::GenericSelectionExprClass:
+ S = cast<Expr>(S)->IgnoreParens();
firstCharOnly = true;
continue;
case Stmt::BinaryConditionalOperatorClass:
diff --git a/lib/StaticAnalyzer/Core/Environment.cpp b/lib/StaticAnalyzer/Core/Environment.cpp
index 1bffa30..1ebb4ac 100644
--- a/lib/StaticAnalyzer/Core/Environment.cpp
+++ b/lib/StaticAnalyzer/Core/Environment.cpp
@@ -41,6 +41,10 @@
// ParenExprs are no-ops.
E = cast<ParenExpr>(E)->getSubExpr();
continue;
+ case Stmt::GenericSelectionExprClass:
+ // GenericSelectionExprs are no-ops.
+ E = cast<GenericSelectionExpr>(E)->getResultExpr();
+ continue;
case Stmt::CharacterLiteralClass: {
const CharacterLiteral* C = cast<CharacterLiteral>(E);
return svalBuilder.makeIntVal(C->getValue(), C->getType());
diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 477292f..621b46e 100644
--- a/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -458,6 +458,8 @@
case Stmt::ParenExprClass:
llvm_unreachable("ParenExprs already handled.");
+ case Stmt::GenericSelectionExprClass:
+ llvm_unreachable("GenericSelectionExprs already handled.");
// Cases that should never be evaluated simply because they shouldn't
// appear in the CFG.
case Stmt::BreakStmtClass: