if (Ty->isSpecificBuiltinType(BuiltinType::Float))
E = ImpCastExprToType(E, Context.DoubleTy, CK_FloatingCast).take();
- // C++ includes lvalue-to-rvalue conversion as a default argument
- // promotion. If we have a gl-value, initialize a temporary.
- if (getLangOptions().CPlusPlus && E->isGLValue()) {
+ // C++ performs lvalue-to-rvalue conversion as a default argument
+ // promotion. If we still have a gl-value after usual unary
+ // conversion, we must have an l-value of class type, so we need to
+ // initialize a temporary. For compatibility reasons, however, we
+ // don't want to do this in unevaluated contexts; otherwise we
+ // reject metaprograms which work by passing uncopyable l-values to
+ // variadic functions.
+ if (getLangOptions().CPlusPlus && E->isGLValue() &&
+ ExprEvalContexts.back().Context != Unevaluated) {
ExprResult Temp = PerformCopyInitialization(
InitializedEntity::InitializeTemporary(E->getType()),
E->getExprLoc(),
foo(a); // expected-error {{calling a private constructor of class 'test1::A'}} expected-error {{cannot pass object of non-trivial type 'test1::A' through variadic function}}
}
}
+
+// Don't enforce this in an unevaluated context.
+namespace test2 {
+ struct A {
+ A(const A&) = delete; // expected-note {{marked deleted here}}
+ };
+
+ typedef char one[1];
+ typedef char two[2];
+
+ one &meta(bool);
+ two &meta(...);
+
+ void a(A &a) {
+ char check[sizeof(meta(a)) == 2 ? 1 : -1];
+ }
+
+ void b(A &a) {
+ meta(a); // expected-error {{call to deleted constructor}}
+ }
+}