mirror of https://github.com/microsoft/clang.git
Make IgnoreParens() look through ChooseExprs.
This is the same way GenericSelectionExpr works, and it's generally a more consistent approach. A large part of this patch is devoted to caching the value of the condition of a ChooseExpr; it's needed to avoid threading an ASTContext into IgnoreParens(). Fixes <rdar://problem/14438917>. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@186738 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
4384712b3a
commit
a5e660188a
|
@ -53,7 +53,7 @@ public:
|
|||
if (E->getCond()->isValueDependent())
|
||||
return;
|
||||
// Only the selected subexpression matters; the other one is not evaluated.
|
||||
return this->Visit(E->getChosenSubExpr(Context));
|
||||
return this->Visit(E->getChosenSubExpr());
|
||||
}
|
||||
|
||||
void VisitDesignatedInitExpr(DesignatedInitExpr *E) {
|
||||
|
|
|
@ -3475,10 +3475,12 @@ class ChooseExpr : public Expr {
|
|||
enum { COND, LHS, RHS, END_EXPR };
|
||||
Stmt* SubExprs[END_EXPR]; // Left/Middle/Right hand sides.
|
||||
SourceLocation BuiltinLoc, RParenLoc;
|
||||
bool CondIsTrue;
|
||||
public:
|
||||
ChooseExpr(SourceLocation BLoc, Expr *cond, Expr *lhs, Expr *rhs,
|
||||
QualType t, ExprValueKind VK, ExprObjectKind OK,
|
||||
SourceLocation RP, bool TypeDependent, bool ValueDependent)
|
||||
SourceLocation RP, bool condIsTrue,
|
||||
bool TypeDependent, bool ValueDependent)
|
||||
: Expr(ChooseExprClass, t, VK, OK, TypeDependent, ValueDependent,
|
||||
(cond->isInstantiationDependent() ||
|
||||
lhs->isInstantiationDependent() ||
|
||||
|
@ -3486,7 +3488,7 @@ public:
|
|||
(cond->containsUnexpandedParameterPack() ||
|
||||
lhs->containsUnexpandedParameterPack() ||
|
||||
rhs->containsUnexpandedParameterPack())),
|
||||
BuiltinLoc(BLoc), RParenLoc(RP) {
|
||||
BuiltinLoc(BLoc), RParenLoc(RP), CondIsTrue(condIsTrue) {
|
||||
SubExprs[COND] = cond;
|
||||
SubExprs[LHS] = lhs;
|
||||
SubExprs[RHS] = rhs;
|
||||
|
@ -3497,12 +3499,21 @@ public:
|
|||
|
||||
/// isConditionTrue - Return whether the condition is true (i.e. not
|
||||
/// equal to zero).
|
||||
bool isConditionTrue(const ASTContext &C) const;
|
||||
bool isConditionTrue() const {
|
||||
assert(!isConditionDependent() &&
|
||||
"Dependent condition isn't true or false");
|
||||
return CondIsTrue;
|
||||
}
|
||||
void setIsConditionTrue(bool isTrue) { CondIsTrue = isTrue; }
|
||||
|
||||
bool isConditionDependent() const {
|
||||
return getCond()->isTypeDependent() || getCond()->isValueDependent();
|
||||
}
|
||||
|
||||
/// getChosenSubExpr - Return the subexpression chosen according to the
|
||||
/// condition.
|
||||
Expr *getChosenSubExpr(const ASTContext &C) const {
|
||||
return isConditionTrue(C) ? getLHS() : getRHS();
|
||||
Expr *getChosenSubExpr() const {
|
||||
return isConditionTrue() ? getLHS() : getRHS();
|
||||
}
|
||||
|
||||
Expr *getCond() const { return cast<Expr>(SubExprs[COND]); }
|
||||
|
|
|
@ -1929,6 +1929,9 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc,
|
|||
case GenericSelectionExprClass:
|
||||
return cast<GenericSelectionExpr>(this)->getResultExpr()->
|
||||
isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx);
|
||||
case ChooseExprClass:
|
||||
return cast<ChooseExpr>(this)->getChosenSubExpr()->
|
||||
isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx);
|
||||
case UnaryOperatorClass: {
|
||||
const UnaryOperator *UO = cast<UnaryOperator>(this);
|
||||
|
||||
|
@ -2295,6 +2298,12 @@ Expr* Expr::IgnoreParens() {
|
|||
continue;
|
||||
}
|
||||
}
|
||||
if (ChooseExpr* P = dyn_cast<ChooseExpr>(E)) {
|
||||
if (!P->isConditionDependent()) {
|
||||
E = P->getChosenSubExpr();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return E;
|
||||
}
|
||||
}
|
||||
|
@ -2304,26 +2313,11 @@ Expr* Expr::IgnoreParens() {
|
|||
Expr *Expr::IgnoreParenCasts() {
|
||||
Expr *E = this;
|
||||
while (true) {
|
||||
if (ParenExpr* P = dyn_cast<ParenExpr>(E)) {
|
||||
E = P->getSubExpr();
|
||||
continue;
|
||||
}
|
||||
E = E->IgnoreParens();
|
||||
if (CastExpr *P = dyn_cast<CastExpr>(E)) {
|
||||
E = P->getSubExpr();
|
||||
continue;
|
||||
}
|
||||
if (UnaryOperator* P = dyn_cast<UnaryOperator>(E)) {
|
||||
if (P->getOpcode() == UO_Extension) {
|
||||
E = P->getSubExpr();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (GenericSelectionExpr* P = dyn_cast<GenericSelectionExpr>(E)) {
|
||||
if (!P->isResultDependent()) {
|
||||
E = P->getResultExpr();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (MaterializeTemporaryExpr *Materialize
|
||||
= dyn_cast<MaterializeTemporaryExpr>(E)) {
|
||||
E = Materialize->GetTemporaryExpr();
|
||||
|
@ -2345,24 +2339,12 @@ Expr *Expr::IgnoreParenCasts() {
|
|||
Expr *Expr::IgnoreParenLValueCasts() {
|
||||
Expr *E = this;
|
||||
while (true) {
|
||||
if (ParenExpr *P = dyn_cast<ParenExpr>(E)) {
|
||||
E = P->getSubExpr();
|
||||
continue;
|
||||
} else if (CastExpr *P = dyn_cast<CastExpr>(E)) {
|
||||
E = E->IgnoreParens();
|
||||
if (CastExpr *P = dyn_cast<CastExpr>(E)) {
|
||||
if (P->getCastKind() == CK_LValueToRValue) {
|
||||
E = P->getSubExpr();
|
||||
continue;
|
||||
}
|
||||
} else if (UnaryOperator* P = dyn_cast<UnaryOperator>(E)) {
|
||||
if (P->getOpcode() == UO_Extension) {
|
||||
E = P->getSubExpr();
|
||||
continue;
|
||||
}
|
||||
} else if (GenericSelectionExpr* P = dyn_cast<GenericSelectionExpr>(E)) {
|
||||
if (!P->isResultDependent()) {
|
||||
E = P->getResultExpr();
|
||||
continue;
|
||||
}
|
||||
} else if (MaterializeTemporaryExpr *Materialize
|
||||
= dyn_cast<MaterializeTemporaryExpr>(E)) {
|
||||
E = Materialize->GetTemporaryExpr();
|
||||
|
@ -2380,10 +2362,7 @@ Expr *Expr::IgnoreParenLValueCasts() {
|
|||
Expr *Expr::ignoreParenBaseCasts() {
|
||||
Expr *E = this;
|
||||
while (true) {
|
||||
if (ParenExpr *P = dyn_cast<ParenExpr>(E)) {
|
||||
E = P->getSubExpr();
|
||||
continue;
|
||||
}
|
||||
E = E->IgnoreParens();
|
||||
if (CastExpr *CE = dyn_cast<CastExpr>(E)) {
|
||||
if (CE->getCastKind() == CK_DerivedToBase ||
|
||||
CE->getCastKind() == CK_UncheckedDerivedToBase ||
|
||||
|
@ -2400,26 +2379,11 @@ Expr *Expr::ignoreParenBaseCasts() {
|
|||
Expr *Expr::IgnoreParenImpCasts() {
|
||||
Expr *E = this;
|
||||
while (true) {
|
||||
if (ParenExpr *P = dyn_cast<ParenExpr>(E)) {
|
||||
E = P->getSubExpr();
|
||||
continue;
|
||||
}
|
||||
E = E->IgnoreParens();
|
||||
if (ImplicitCastExpr *P = dyn_cast<ImplicitCastExpr>(E)) {
|
||||
E = P->getSubExpr();
|
||||
continue;
|
||||
}
|
||||
if (UnaryOperator* P = dyn_cast<UnaryOperator>(E)) {
|
||||
if (P->getOpcode() == UO_Extension) {
|
||||
E = P->getSubExpr();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (GenericSelectionExpr* P = dyn_cast<GenericSelectionExpr>(E)) {
|
||||
if (!P->isResultDependent()) {
|
||||
E = P->getResultExpr();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (MaterializeTemporaryExpr *Materialize
|
||||
= dyn_cast<MaterializeTemporaryExpr>(E)) {
|
||||
E = Materialize->GetTemporaryExpr();
|
||||
|
@ -2448,10 +2412,7 @@ Expr *Expr::IgnoreConversionOperator() {
|
|||
Expr *Expr::IgnoreParenNoopCasts(ASTContext &Ctx) {
|
||||
Expr *E = this;
|
||||
while (true) {
|
||||
if (ParenExpr *P = dyn_cast<ParenExpr>(E)) {
|
||||
E = P->getSubExpr();
|
||||
continue;
|
||||
}
|
||||
E = E->IgnoreParens();
|
||||
|
||||
if (CastExpr *P = dyn_cast<CastExpr>(E)) {
|
||||
// We ignore integer <-> casts that are of the same width, ptr<->ptr and
|
||||
|
@ -2473,20 +2434,6 @@ Expr *Expr::IgnoreParenNoopCasts(ASTContext &Ctx) {
|
|||
}
|
||||
}
|
||||
|
||||
if (UnaryOperator* P = dyn_cast<UnaryOperator>(E)) {
|
||||
if (P->getOpcode() == UO_Extension) {
|
||||
E = P->getSubExpr();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (GenericSelectionExpr* P = dyn_cast<GenericSelectionExpr>(E)) {
|
||||
if (!P->isResultDependent()) {
|
||||
E = P->getResultExpr();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (SubstNonTypeTemplateParmExpr *NTTP
|
||||
= dyn_cast<SubstNonTypeTemplateParmExpr>(E)) {
|
||||
E = NTTP->getReplacement();
|
||||
|
@ -2728,7 +2675,9 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const {
|
|||
return cast<GenericSelectionExpr>(this)->getResultExpr()
|
||||
->isConstantInitializer(Ctx, IsForRef);
|
||||
case ChooseExprClass:
|
||||
return cast<ChooseExpr>(this)->getChosenSubExpr(Ctx)
|
||||
if (cast<ChooseExpr>(this)->isConditionDependent())
|
||||
return false;
|
||||
return cast<ChooseExpr>(this)->getChosenSubExpr()
|
||||
->isConstantInitializer(Ctx, IsForRef);
|
||||
case UnaryOperatorClass: {
|
||||
const UnaryOperator* Exp = cast<UnaryOperator>(this);
|
||||
|
@ -2887,7 +2836,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx) const {
|
|||
HasSideEffects(Ctx);
|
||||
|
||||
case ChooseExprClass:
|
||||
return cast<ChooseExpr>(this)->getChosenSubExpr(Ctx)->HasSideEffects(Ctx);
|
||||
return cast<ChooseExpr>(this)->getChosenSubExpr()->HasSideEffects(Ctx);
|
||||
|
||||
case CXXDefaultArgExprClass:
|
||||
return cast<CXXDefaultArgExpr>(this)->getExpr()->HasSideEffects(Ctx);
|
||||
|
@ -3082,7 +3031,13 @@ Expr::isNullPointerConstant(ASTContext &Ctx,
|
|||
return PE->getSubExpr()->isNullPointerConstant(Ctx, NPC);
|
||||
} else if (const GenericSelectionExpr *GE =
|
||||
dyn_cast<GenericSelectionExpr>(this)) {
|
||||
if (GE->isResultDependent())
|
||||
return NPCK_NotNull;
|
||||
return GE->getResultExpr()->isNullPointerConstant(Ctx, NPC);
|
||||
} else if (const ChooseExpr *CE = dyn_cast<ChooseExpr>(this)) {
|
||||
if (CE->isConditionDependent())
|
||||
return NPCK_NotNull;
|
||||
return CE->getChosenSubExpr()->isNullPointerConstant(Ctx, NPC);
|
||||
} else if (const CXXDefaultArgExpr *DefaultArg
|
||||
= dyn_cast<CXXDefaultArgExpr>(this)) {
|
||||
// See through default argument expressions.
|
||||
|
@ -3567,10 +3522,6 @@ StringRef ObjCBridgedCastExpr::getBridgeKindName() const {
|
|||
llvm_unreachable("Invalid BridgeKind!");
|
||||
}
|
||||
|
||||
bool ChooseExpr::isConditionTrue(const ASTContext &C) const {
|
||||
return getCond()->EvaluateKnownConstInt(C) != 0;
|
||||
}
|
||||
|
||||
ShuffleVectorExpr::ShuffleVectorExpr(ASTContext &C, ArrayRef<Expr*> args,
|
||||
QualType Type, SourceLocation BLoc,
|
||||
SourceLocation RP)
|
||||
|
|
|
@ -286,7 +286,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
|
|||
|
||||
// __builtin_choose_expr is equivalent to the chosen expression.
|
||||
case Expr::ChooseExprClass:
|
||||
return ClassifyInternal(Ctx, cast<ChooseExpr>(E)->getChosenSubExpr(Ctx));
|
||||
return ClassifyInternal(Ctx, cast<ChooseExpr>(E)->getChosenSubExpr());
|
||||
|
||||
// Extended vector element access is an lvalue unless there are duplicates
|
||||
// in the shuffle expression.
|
||||
|
|
|
@ -3585,7 +3585,7 @@ public:
|
|||
RetTy VisitUnaryPlus(const UnaryOperator *E)
|
||||
{ return StmtVisitorTy::Visit(E->getSubExpr()); }
|
||||
RetTy VisitChooseExpr(const ChooseExpr *E)
|
||||
{ return StmtVisitorTy::Visit(E->getChosenSubExpr(Info.Ctx)); }
|
||||
{ return StmtVisitorTy::Visit(E->getChosenSubExpr()); }
|
||||
RetTy VisitGenericSelectionExpr(const GenericSelectionExpr *E)
|
||||
{ return StmtVisitorTy::Visit(E->getResultExpr()); }
|
||||
RetTy VisitSubstNonTypeTemplateParmExpr(const SubstNonTypeTemplateParmExpr *E)
|
||||
|
@ -8263,7 +8263,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
|
|||
case Expr::CXXDefaultInitExprClass:
|
||||
return CheckICE(cast<CXXDefaultInitExpr>(E)->getExpr(), Ctx);
|
||||
case Expr::ChooseExprClass: {
|
||||
return CheckICE(cast<ChooseExpr>(E)->getChosenSubExpr(Ctx), Ctx);
|
||||
return CheckICE(cast<ChooseExpr>(E)->getChosenSubExpr(), Ctx);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -851,7 +851,7 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) {
|
|||
case Expr::BinaryConditionalOperatorClass:
|
||||
return EmitConditionalOperatorLValue(cast<BinaryConditionalOperator>(E));
|
||||
case Expr::ChooseExprClass:
|
||||
return EmitLValue(cast<ChooseExpr>(E)->getChosenSubExpr(getContext()));
|
||||
return EmitLValue(cast<ChooseExpr>(E)->getChosenSubExpr());
|
||||
case Expr::OpaqueValueExprClass:
|
||||
return EmitOpaqueValueLValue(cast<OpaqueValueExpr>(E));
|
||||
case Expr::SubstNonTypeTemplateParmExprClass:
|
||||
|
|
|
@ -920,7 +920,7 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
|
|||
}
|
||||
|
||||
void AggExprEmitter::VisitChooseExpr(const ChooseExpr *CE) {
|
||||
Visit(CE->getChosenSubExpr(CGF.getContext()));
|
||||
Visit(CE->getChosenSubExpr());
|
||||
}
|
||||
|
||||
void AggExprEmitter::VisitVAArgExpr(VAArgExpr *VE) {
|
||||
|
|
|
@ -778,7 +778,7 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
|
|||
}
|
||||
|
||||
ComplexPairTy ComplexExprEmitter::VisitChooseExpr(ChooseExpr *E) {
|
||||
return Visit(E->getChosenSubExpr(CGF.getContext()));
|
||||
return Visit(E->getChosenSubExpr());
|
||||
}
|
||||
|
||||
ComplexPairTy ComplexExprEmitter::VisitInitListExpr(InitListExpr *E) {
|
||||
|
|
|
@ -610,7 +610,7 @@ public:
|
|||
}
|
||||
|
||||
llvm::Constant *VisitChooseExpr(ChooseExpr *CE) {
|
||||
return Visit(CE->getChosenSubExpr(CGM.getContext()));
|
||||
return Visit(CE->getChosenSubExpr());
|
||||
}
|
||||
|
||||
llvm::Constant *VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
|
||||
|
|
|
@ -3101,7 +3101,7 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
|
|||
}
|
||||
|
||||
Value *ScalarExprEmitter::VisitChooseExpr(ChooseExpr *E) {
|
||||
return Visit(E->getChosenSubExpr(CGF.getContext()));
|
||||
return Visit(E->getChosenSubExpr());
|
||||
}
|
||||
|
||||
Value *ScalarExprEmitter::VisitVAArgExpr(VAArgExpr *VE) {
|
||||
|
|
|
@ -1025,7 +1025,7 @@ CanThrowResult Sema::canThrow(const Expr *E) {
|
|||
case Expr::ChooseExprClass:
|
||||
if (E->isTypeDependent() || E->isValueDependent())
|
||||
return CT_Dependent;
|
||||
return canThrow(cast<ChooseExpr>(E)->getChosenSubExpr(Context));
|
||||
return canThrow(cast<ChooseExpr>(E)->getChosenSubExpr());
|
||||
|
||||
case Expr::GenericSelectionExprClass:
|
||||
if (cast<GenericSelectionExpr>(E)->isResultDependent())
|
||||
|
|
|
@ -9868,6 +9868,7 @@ ExprResult Sema::ActOnChooseExpr(SourceLocation BuiltinLoc,
|
|||
ExprObjectKind OK = OK_Ordinary;
|
||||
QualType resType;
|
||||
bool ValueDependent = false;
|
||||
bool CondIsTrue = false;
|
||||
if (CondExpr->isTypeDependent() || CondExpr->isValueDependent()) {
|
||||
resType = Context.DependentTy;
|
||||
ValueDependent = true;
|
||||
|
@ -9880,9 +9881,10 @@ ExprResult Sema::ActOnChooseExpr(SourceLocation BuiltinLoc,
|
|||
if (CondICE.isInvalid())
|
||||
return ExprError();
|
||||
CondExpr = CondICE.take();
|
||||
CondIsTrue = condEval.getZExtValue();
|
||||
|
||||
// If the condition is > zero, then the AST type is the same as the LSHExpr.
|
||||
Expr *ActiveExpr = condEval.getZExtValue() ? LHSExpr : RHSExpr;
|
||||
Expr *ActiveExpr = CondIsTrue ? LHSExpr : RHSExpr;
|
||||
|
||||
resType = ActiveExpr->getType();
|
||||
ValueDependent = ActiveExpr->isValueDependent();
|
||||
|
@ -9891,7 +9893,7 @@ ExprResult Sema::ActOnChooseExpr(SourceLocation BuiltinLoc,
|
|||
}
|
||||
|
||||
return Owned(new (Context) ChooseExpr(BuiltinLoc, CondExpr, LHSExpr, RHSExpr,
|
||||
resType, VK, OK, RPLoc,
|
||||
resType, VK, OK, RPLoc, CondIsTrue,
|
||||
resType->isDependentType(),
|
||||
ValueDependent));
|
||||
}
|
||||
|
|
|
@ -101,6 +101,25 @@ namespace {
|
|||
resultIndex);
|
||||
}
|
||||
|
||||
if (ChooseExpr *ce = dyn_cast<ChooseExpr>(e)) {
|
||||
assert(!ce->isConditionDependent());
|
||||
|
||||
Expr *LHS = ce->getLHS(), *RHS = ce->getRHS();
|
||||
Expr *&rebuiltExpr = ce->isConditionTrue() ? LHS : RHS;
|
||||
rebuiltExpr = rebuild(rebuiltExpr);
|
||||
|
||||
return new (S.Context) ChooseExpr(ce->getBuiltinLoc(),
|
||||
ce->getCond(),
|
||||
LHS, RHS,
|
||||
rebuiltExpr->getType(),
|
||||
rebuiltExpr->getValueKind(),
|
||||
rebuiltExpr->getObjectKind(),
|
||||
ce->getRParenLoc(),
|
||||
ce->isConditionTrue(),
|
||||
rebuiltExpr->isTypeDependent(),
|
||||
rebuiltExpr->isValueDependent());
|
||||
}
|
||||
|
||||
llvm_unreachable("bad expression to rebuild!");
|
||||
}
|
||||
};
|
||||
|
|
|
@ -835,6 +835,7 @@ void ASTStmtReader::VisitChooseExpr(ChooseExpr *E) {
|
|||
E->setRHS(Reader.ReadSubExpr());
|
||||
E->setBuiltinLoc(ReadSourceLocation(Record, Idx));
|
||||
E->setRParenLoc(ReadSourceLocation(Record, Idx));
|
||||
E->setIsConditionTrue(Record[Idx++]);
|
||||
}
|
||||
|
||||
void ASTStmtReader::VisitGNUNullExpr(GNUNullExpr *E) {
|
||||
|
|
|
@ -773,6 +773,7 @@ void ASTStmtWriter::VisitChooseExpr(ChooseExpr *E) {
|
|||
Writer.AddStmt(E->getRHS());
|
||||
Writer.AddSourceLocation(E->getBuiltinLoc(), Record);
|
||||
Writer.AddSourceLocation(E->getRParenLoc(), Record);
|
||||
Record.push_back(E->isConditionDependent() ? false : E->isConditionTrue());
|
||||
Code = serialization::EXPR_CHOOSE;
|
||||
}
|
||||
|
||||
|
|
|
@ -678,19 +678,8 @@ bool IdempotentOperationChecker::CanVary(const Expr *Ex,
|
|||
return CanVary(B->getRHS(), AC)
|
||||
|| CanVary(B->getLHS(), AC);
|
||||
}
|
||||
case Stmt::UnaryOperatorClass: {
|
||||
const UnaryOperator *U = cast<const UnaryOperator>(Ex);
|
||||
// Handle trivial case first
|
||||
switch (U->getOpcode()) {
|
||||
case UO_Extension:
|
||||
return false;
|
||||
default:
|
||||
return CanVary(U->getSubExpr(), AC);
|
||||
}
|
||||
}
|
||||
case Stmt::ChooseExprClass:
|
||||
return CanVary(cast<const ChooseExpr>(Ex)->getChosenSubExpr(
|
||||
AC->getASTContext()), AC);
|
||||
case Stmt::UnaryOperatorClass:
|
||||
return CanVary(cast<UnaryOperator>(Ex)->getSubExpr(), AC);
|
||||
case Stmt::ConditionalOperatorClass:
|
||||
case Stmt::BinaryConditionalOperatorClass:
|
||||
return CanVary(cast<AbstractConditionalOperator>(Ex)->getCond(), AC);
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
|
||||
// expected-no-diagnostics
|
||||
|
||||
@interface NSArray
|
||||
-(int)count;
|
||||
@end
|
||||
|
||||
// <rdar://problem/14438917>
|
||||
char* f(NSArray *array) {
|
||||
return _Generic(__builtin_choose_expr(__builtin_types_compatible_p(__typeof__(array.count), void), 0.f, array.count),
|
||||
unsigned int:"uint",
|
||||
float:"void",
|
||||
default: "ignored");
|
||||
}
|
Loading…
Reference in New Issue