diff options
-rw-r--r-- | include/clang/Basic/Builtins.def | 2 | ||||
-rw-r--r-- | lib/Sema/SemaChecking.cpp | 29 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 30 | ||||
-rw-r--r-- | test/CXX/special/class.temporary/p1.cpp | 37 | ||||
-rw-r--r-- | test/CodeGenCXX/varargs.cpp | 46 |
5 files changed, 116 insertions, 28 deletions
diff --git a/include/clang/Basic/Builtins.def b/include/clang/Basic/Builtins.def index d12a04d8f1..50cf872668 100644 --- a/include/clang/Basic/Builtins.def +++ b/include/clang/Basic/Builtins.def @@ -389,7 +389,7 @@ BUILTIN(__builtin_constant_p, "i.", "nct") BUILTIN(__builtin_classify_type, "i.", "nct") BUILTIN(__builtin___CFStringMakeConstantString, "FC*cC*", "nc") BUILTIN(__builtin___NSStringMakeConstantString, "FC*cC*", "nc") -BUILTIN(__builtin_va_start, "vA.", "n") +BUILTIN(__builtin_va_start, "vA.", "nt") BUILTIN(__builtin_va_end, "vA", "n") BUILTIN(__builtin_va_copy, "vAA", "n") BUILTIN(__builtin_stdarg_start, "vA.", "n") diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 530f81289a..30c247f987 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -12,6 +12,7 @@ // //===----------------------------------------------------------------------===// +#include "clang/Sema/Initialization.h" #include "clang/Sema/Sema.h" #include "clang/Sema/SemaInternal.h" #include "clang/Sema/ScopeInfo.h" @@ -396,6 +397,30 @@ bool Sema::CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall) { return false; } +/// checkBuiltinArgument - Given a call to a builtin function, perform +/// normal type-checking on the given argument, updating the call in +/// place. This is useful when a builtin function requires custom +/// type-checking for some of its arguments but not necessarily all of +/// them. +/// +/// Returns true on error. +static bool checkBuiltinArgument(Sema &S, CallExpr *E, unsigned ArgIndex) { + FunctionDecl *Fn = E->getDirectCallee(); + assert(Fn && "builtin call without direct callee!"); + + ParmVarDecl *Param = Fn->getParamDecl(ArgIndex); + InitializedEntity Entity = + InitializedEntity::InitializeParameter(S.Context, Param); + + ExprResult Arg = E->getArg(0); + Arg = S.PerformCopyInitialization(Entity, SourceLocation(), Arg); + if (Arg.isInvalid()) + return true; + + E->setArg(ArgIndex, Arg.take()); + return false; +} + /// SemaBuiltinAtomicOverloaded - We have a call to a function like /// __sync_fetch_and_add, which is an overloaded function based on the pointer /// type of its first argument. The main ActOnCallExpr routines have already @@ -661,6 +686,10 @@ bool Sema::SemaBuiltinVAStart(CallExpr *TheCall) { << 0 /*function call*/ << 2 << TheCall->getNumArgs(); } + // Type-check the first argument normally. + if (checkBuiltinArgument(*this, TheCall, 0)) + return true; + // Determine whether the current function is variadic or not. BlockScopeInfo *CurBlock = getCurBlock(); bool isVariadic; diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 28ec97f652..65c9cccaf1 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -443,6 +443,18 @@ 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()) { + ExprResult Temp = PerformCopyInitialization( + InitializedEntity::InitializeTemporary(E->getType()), + E->getExprLoc(), + Owned(E)); + if (Temp.isInvalid()) + return ExprError(); + E = Temp.get(); + } + return Owned(E); } @@ -460,19 +472,13 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT, return ExprError(); E = ExprRes.take(); - // __builtin_va_start takes the second argument as a "varargs" argument, but - // it doesn't actually do anything with it. It doesn't need to be non-pod - // etc. - 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)) return ExprError(); - + if (!E->getType().isPODType(Context)) { // C++0x [expr.call]p7: // Passing a potentially-evaluated argument of class type (Clause 9) @@ -519,16 +525,6 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT, if (Comma.isInvalid()) return ExprError(); E = Comma.get(); - - // Use that to initialize a temporary, or else we might get an - // l-value in a varargs position. - ExprResult Temp = PerformCopyInitialization( - InitializedEntity::InitializeTemporary(E->getType()), - E->getLocStart(), - Owned(E)); - if (Temp.isInvalid()) - return ExprError(); - E = Temp.get(); } } diff --git a/test/CXX/special/class.temporary/p1.cpp b/test/CXX/special/class.temporary/p1.cpp new file mode 100644 index 0000000000..e3b8f9ce66 --- /dev/null +++ b/test/CXX/special/class.temporary/p1.cpp @@ -0,0 +1,37 @@ +// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s + +namespace test0 { + struct A { + A() = default; + int x; + int y; + + A(const A&) = delete; // expected-note {{function has been explicitly marked deleted here}} + }; + + void foo(...); + + void test() { + A a; + foo(a); // expected-error {{call to deleted constructor of 'test0::A'}} + } +} + +namespace test1 { + struct A { + A() = default; + int x; + int y; + + private: + A(const A&) = default; // expected-note {{declared private here}} + }; + + void foo(...); + + void test() { + A a; + // FIXME: this error about variadics is bogus + 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}} + } +} diff --git a/test/CodeGenCXX/varargs.cpp b/test/CodeGenCXX/varargs.cpp index d469ae4f23..af34336a0a 100644 --- a/test/CodeGenCXX/varargs.cpp +++ b/test/CodeGenCXX/varargs.cpp @@ -1,17 +1,43 @@ -// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck %s + // rdar://7309675 // PR4678 +namespace test0 { + // test1 should be compmiled to be a varargs function in the IR even + // though there is no way to do a va_begin. Otherwise, the optimizer + // will warn about 'dropped arguments' at the call site. -// test1 should be compmiled to be a varargs function in the IR even -// though there is no way to do a va_begin. Otherwise, the optimizer -// will warn about 'dropped arguments' at the call site. + // CHECK: define i32 @_ZN5test05test1Ez(...) + int test1(...) { + return -1; + } -// CHECK: define i32 @_Z5test1z(...) -int test1(...) { - return -1; + // CHECK: call i32 (...)* @_ZN5test05test1Ez(i32 0) + void test() { + test1(0); + } } -// CHECK: call i32 (...)* @_Z5test1z(i32 0) -void test() { - test1(0); +namespace test1 { + struct A { + int x; + int y; + }; + + void foo(...); + + void test() { + A x; + foo(x); + } + // CHECK: define void @_ZN5test14testEv() + // CHECK: [[X:%.*]] = alloca [[A:%.*]], align 4 + // CHECK-NEXT: [[TMP:%.*]] = alloca [[A]], align 4 + // CHECK-NEXT: [[T0:%.*]] = bitcast [[A]]* [[TMP]] to i8* + // CHECK-NEXT: [[T1:%.*]] = bitcast [[A]]* [[X]] to i8* + // CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[T0]], i8* [[T1]], i64 8, i32 4, i1 false) + // CHECK-NEXT: [[T0:%.*]] = bitcast [[A]]* [[TMP]] to i64* + // CHECK-NEXT: [[T1:%.*]] = load i64* [[T0]], align 1 + // CHECK-NEXT: call void (...)* @_ZN5test13fooEz(i64 [[T1]]) + // CHECK-NEXT: ret void } |