]> granicus.if.org Git - clang/commitdiff
Disable the l-value to r-value conversion on C++ class types passed
authorJohn McCall <rjmccall@apple.com>
Sat, 27 Aug 2011 22:06:17 +0000 (22:06 +0000)
committerJohn McCall <rjmccall@apple.com>
Sat, 27 Aug 2011 22:06:17 +0000 (22:06 +0000)
to varargs functions in unevaluated contexts.  AFAICT, there is no
standards justification for this, but it matches what other compilers do
and therefore preserves compatibility with certain template metaprogramming
idioms.

Should fix self-host.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@138715 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaExpr.cpp
test/CXX/special/class.temporary/p1.cpp

index 65c9cccaf11b515375a39a7a18ecfa5315d799dd..6327ee71db13576f5201acea22faca2497e47924 100644 (file)
@@ -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(),
index e3b8f9ce6698cc2bac8a8351ee8866cee4830c3d..07890eb297de6cbfb22cfb68f01e3144f81318ea 100644 (file)
@@ -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}}
+  }
+}