aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/Sema/SemaExpr.cpp12
-rw-r--r--test/CXX/special/class.temporary/p1.cpp21
2 files changed, 30 insertions, 3 deletions
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 65c9cccaf1..6327ee71db 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -443,9 +443,15 @@ ExprResult Sema::DefaultArgumentPromotion(Expr *E) {
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(),
diff --git a/test/CXX/special/class.temporary/p1.cpp b/test/CXX/special/class.temporary/p1.cpp
index e3b8f9ce66..07890eb297 100644
--- a/test/CXX/special/class.temporary/p1.cpp
+++ b/test/CXX/special/class.temporary/p1.cpp
@@ -35,3 +35,24 @@ namespace test1 {
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}}
+ }
+}