diff options
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 34 | ||||
-rw-r--r-- | test/CodeGenCXX/vararg-non-pod.cpp | 16 | ||||
-rw-r--r-- | test/SemaCXX/vararg-non-pod.cpp | 9 |
3 files changed, 49 insertions, 10 deletions
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 6bccdaeb24..ce929d58ee 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -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 index 0000000000..6c6f459ce5 --- /dev/null +++ b/test/CodeGenCXX/vararg-non-pod.cpp @@ -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 +} diff --git a/test/SemaCXX/vararg-non-pod.cpp b/test/SemaCXX/vararg-non-pod.cpp index 55ec9418cd..df0080fac9 100644 --- a/test/SemaCXX/vararg-non-pod.cpp +++ b/test/SemaCXX/vararg-non-pod.cpp @@ -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 |