/// cleanups would have had a side-effect, note that as an unmodeled
/// side-effect and return false. Otherwise, return true.
bool discardCleanups() {
- for (Cleanup &C : CleanupStack)
- if (C.hasSideEffect())
- if (!noteSideEffect())
- return false;
+ for (Cleanup &C : CleanupStack) {
+ if (C.hasSideEffect() && !noteSideEffect()) {
+ CleanupStack.clear();
+ return false;
+ }
+ }
+ CleanupStack.clear();
return true;
}
assert(MD && "Don't provide `this` for non-methods.");
assert(!MD->isStatic() && "Don't provide `this` for static methods.");
#endif
- if (EvaluateObjectArgument(Info, This, ThisVal))
+ if (!This->isValueDependent() &&
+ EvaluateObjectArgument(Info, This, ThisVal) &&
+ !Info.EvalStatus.HasSideEffects)
ThisPtr = &ThisVal;
- if (Info.EvalStatus.HasSideEffects)
- return false;
+
+ // Ignore any side-effects from a failed evaluation. This is safe because
+ // they can't interfere with any other argument evaluation.
+ Info.EvalStatus.HasSideEffects = false;
}
ArgVector ArgValues(Args.size());
for (ArrayRef<const Expr*>::iterator I = Args.begin(), E = Args.end();
I != E; ++I) {
if ((*I)->isValueDependent() ||
- !Evaluate(ArgValues[I - Args.begin()], Info, *I))
+ !Evaluate(ArgValues[I - Args.begin()], Info, *I) ||
+ Info.EvalStatus.HasSideEffects)
// If evaluation fails, throw away the argument entirely.
ArgValues[I - Args.begin()] = APValue();
- if (Info.EvalStatus.HasSideEffects)
- return false;
+
+ // Ignore any side-effects from a failed evaluation. This is safe because
+ // they can't interfere with any other argument evaluation.
+ Info.EvalStatus.HasSideEffects = false;
}
+ // Parameter cleanups happen in the caller and are not part of this
+ // evaluation.
+ Info.discardCleanups();
+ Info.EvalStatus.HasSideEffects = false;
+
// Build fake call to Callee.
CallStackFrame Frame(Info, Callee->getLocation(), Callee, ThisPtr,
ArgValues.data());
- return Evaluate(Value, Info, this) && Info.discardCleanups() &&
+ // FIXME: Missing ExprWithCleanups in enable_if conditions?
+ FullExpressionRAII Scope(Info);
+ return Evaluate(Value, Info, this) && Scope.destroy() &&
!Info.EvalStatus.HasSideEffects;
}
// RUN: %clang_cc1 -std=c++11 -verify %s
-
+// RUN: %clang_cc1 -std=c++2a -verify %s
typedef int (*fp)(int);
int surrogate(int);
struct Incomplete; // expected-note{{forward declaration of 'Incomplete'}} \
}
}
+namespace IgnoreUnusedArgSideEffects {
+ struct A { ~A(); };
+ void f(A a, bool b) __attribute__((enable_if(b, ""))); // expected-note 2-3{{disabled}}
+ void test() {
+ f(A(), true);
+ f(A(), false); // expected-error {{no matching function}}
+ int n;
+ f((n = 1, A()), true);
+ f(A(), (n = 1, true)); // expected-error {{no matching function}}
+ f(A(), (A(), true));
+ }
+
+#if __cplusplus > 201702L
+ struct B { constexpr ~B() {} bool b; };
+ void g(B b) __attribute__((enable_if(b.b, ""))); // expected-note {{disabled}}
+ void test2() {
+ g(B{true});
+ g(B{false}); // expected-error {{no matching function}}
+ f(A(), B{true}.b);
+ f(A(), B{false}.b); // expected-error {{no matching function}}
+ }
+
+ // First condition is non-constant due to non-constexpr destructor of A.
+ int &h() __attribute__((enable_if((A(), true), "")));
+ float &h() __attribute__((enable_if((B(), true), "")));
+ float &x = h();
+#endif
+}