]> granicus.if.org Git - clang/commitdiff
Fix our handling of the warning when one tries to pass a
authorDouglas Gregor <dgregor@apple.com>
Sat, 21 May 2011 19:26:31 +0000 (19:26 +0000)
committerDouglas Gregor <dgregor@apple.com>
Sat, 21 May 2011 19:26:31 +0000 (19:26 +0000)
non-POD/non-trivial object throuugh a C-style varargs. The warning
itself was default-mapped to error, but can be downgraded, but we were
treating it in Sema like a hard error, silently dropping the call.

Instead, treat this problem like a warning, and do what the warning
says we do: abort at runtime. To do so, we fake up a __builtin_trap()
expression that gets evaluated as part of the argument.

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

lib/Sema/SemaExpr.cpp
test/CodeGenCXX/vararg-non-pod.cpp [new file with mode: 0644]
test/SemaCXX/vararg-non-pod.cpp

index 6bccdaeb2466314a06c360b8b7781776b7c3fc33..ce929d58ee4c7882a3614cab439351551e63a9ed 100644 (file)
@@ -449,13 +449,13 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT,
   if (FDecl && FDecl->getBuiltinID() == Builtin::BI__builtin_va_start)
     return Owned(E);
   
+  // Don't allow one to pass an Objective-C interface to a vararg.
   if (E->getType()->isObjCObjectType() &&
-      DiagRuntimeBehavior(E->getLocStart(), 0,
-        PDiag(diag::err_cannot_pass_objc_interface_to_vararg)
-          << E->getType() << CT))
+    DiagRuntimeBehavior(E->getLocStart(), 0,
+                        PDiag(diag::err_cannot_pass_objc_interface_to_vararg)
+                          << E->getType() << CT))
     return ExprError();
-
-  // C++ [expr.call]p7 prohibits non-POD types.
+  
   if (!E->getType()->isPODType()) {
     // C++0x [expr.call]p7:
     //   Passing a potentially-evaluated argument of class type (Clause 9) 
@@ -477,8 +477,28 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT,
     } else if (DiagRuntimeBehavior(E->getLocStart(), 0,
                           PDiag(diag::warn_cannot_pass_non_pod_arg_to_vararg)
                             << getLangOptions().CPlusPlus0x << E->getType() 
-                            << CT))
-      return ExprError();
+                            << CT)) {
+      // Turn this into a trap.
+      CXXScopeSpec SS;
+      UnqualifiedId Name;
+      Name.setIdentifier(PP.getIdentifierInfo("__builtin_trap"),
+                         E->getLocStart());
+      ExprResult TrapFn = ActOnIdExpression(TUScope, SS, Name, true, false);
+      if (TrapFn.isInvalid())
+        return ExprError();
+
+      ExprResult Call = ActOnCallExpr(TUScope, TrapFn.get(), E->getLocStart(),
+                                      MultiExprArg(), E->getLocEnd());
+      if (Call.isInvalid())
+        return ExprError();
+      
+      ExprResult Comma = ActOnBinOp(TUScope, E->getLocStart(), tok::comma,
+                                    Call.get(), E);
+      if (Comma.isInvalid())
+        return ExprError();
+      
+      E = Comma.get();
+    }
   }
   
   return Owned(E);
diff --git a/test/CodeGenCXX/vararg-non-pod.cpp b/test/CodeGenCXX/vararg-non-pod.cpp
new file mode 100644 (file)
index 0000000..6c6f459
--- /dev/null
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -Wno-error=non-pod-varargs -emit-llvm -o - %s | FileCheck %s
+
+struct X {
+  X();
+  X(const X&);
+  ~X();
+};
+
+void vararg(...);
+
+// CHECK: define void @_Z4test1X
+void test(X x) {
+  // CHECK: call void @llvm.trap()
+  vararg(x);
+  // CHECK: ret void
+}
index 55ec9418cd47258545b7501dc45910e6edb26ae6..df0080fac94a0f19b8f6f279599b0d752d58821e 100644 (file)
@@ -56,15 +56,18 @@ void t4()
 }
 
 class E {
-  E(int, ...);
+  E(int, ...); // expected-note 2{{implicitly declared private here}}
 };
 
 void t5()
 {
   C c(10);
   
-  E e(10, c); // expected-warning{{cannot pass object of non-POD type 'C' through variadic constructor; call will abort at runtime}}
-  (void)E(10, c); // expected-warning{{cannot pass object of non-POD type 'C' through variadic constructor; call will abort at runtime}}
+  E e(10, c); // expected-warning{{cannot pass object of non-POD type 'C' through variadic constructor; call will abort at runtime}} \
+    // expected-error{{calling a private constructor of class 'E'}}
+  (void)E(10, c); // expected-warning{{cannot pass object of non-POD type 'C' through variadic constructor; call will abort at runtime}} \
+    // expected-error{{calling a private constructor of class 'E'}}
+
 }
 
 // PR5761: unevaluated operands and the non-POD warning