diff options
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 12 | ||||
-rw-r--r-- | test/CXX/special/class.temporary/p1.cpp | 21 |
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}} + } +} |