forked from OSchip/llvm-project
The lvalue-to-rvalue on structs in C++ is actually part
of default argument promotion and needs to happen unconditionally. This is particularly semantically important in C++0x. llvm-svn: 138691
This commit is contained in:
parent
79cfba180a
commit
29ad95b232
|
@ -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")
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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}}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue