Fix our handling of the warning when one tries to pass a

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
This commit is contained in:
Douglas Gregor 2011-05-21 19:26:31 +00:00
Родитель 4d509341bd
Коммит 930a9abb7e
3 изменённых файлов: 49 добавлений и 10 удалений

Просмотреть файл

@ -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);

Просмотреть файл

@ -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
}

Просмотреть файл

@ -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