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_classify_type, "i.", "nct")
|
||||||
BUILTIN(__builtin___CFStringMakeConstantString, "FC*cC*", "nc")
|
BUILTIN(__builtin___CFStringMakeConstantString, "FC*cC*", "nc")
|
||||||
BUILTIN(__builtin___NSStringMakeConstantString, "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_end, "vA", "n")
|
||||||
BUILTIN(__builtin_va_copy, "vAA", "n")
|
BUILTIN(__builtin_va_copy, "vAA", "n")
|
||||||
BUILTIN(__builtin_stdarg_start, "vA.", "n")
|
BUILTIN(__builtin_stdarg_start, "vA.", "n")
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "clang/Sema/Initialization.h"
|
||||||
#include "clang/Sema/Sema.h"
|
#include "clang/Sema/Sema.h"
|
||||||
#include "clang/Sema/SemaInternal.h"
|
#include "clang/Sema/SemaInternal.h"
|
||||||
#include "clang/Sema/ScopeInfo.h"
|
#include "clang/Sema/ScopeInfo.h"
|
||||||
|
@ -396,6 +397,30 @@ bool Sema::CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall) {
|
||||||
return false;
|
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
|
/// SemaBuiltinAtomicOverloaded - We have a call to a function like
|
||||||
/// __sync_fetch_and_add, which is an overloaded function based on the pointer
|
/// __sync_fetch_and_add, which is an overloaded function based on the pointer
|
||||||
/// type of its first argument. The main ActOnCallExpr routines have already
|
/// 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();
|
<< 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.
|
// Determine whether the current function is variadic or not.
|
||||||
BlockScopeInfo *CurBlock = getCurBlock();
|
BlockScopeInfo *CurBlock = getCurBlock();
|
||||||
bool isVariadic;
|
bool isVariadic;
|
||||||
|
|
|
@ -443,6 +443,18 @@ ExprResult Sema::DefaultArgumentPromotion(Expr *E) {
|
||||||
if (Ty->isSpecificBuiltinType(BuiltinType::Float))
|
if (Ty->isSpecificBuiltinType(BuiltinType::Float))
|
||||||
E = ImpCastExprToType(E, Context.DoubleTy, CK_FloatingCast).take();
|
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);
|
return Owned(E);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -460,19 +472,13 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT,
|
||||||
return ExprError();
|
return ExprError();
|
||||||
E = ExprRes.take();
|
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.
|
// Don't allow one to pass an Objective-C interface to a vararg.
|
||||||
if (E->getType()->isObjCObjectType() &&
|
if (E->getType()->isObjCObjectType() &&
|
||||||
DiagRuntimeBehavior(E->getLocStart(), 0,
|
DiagRuntimeBehavior(E->getLocStart(), 0,
|
||||||
PDiag(diag::err_cannot_pass_objc_interface_to_vararg)
|
PDiag(diag::err_cannot_pass_objc_interface_to_vararg)
|
||||||
<< E->getType() << CT))
|
<< E->getType() << CT))
|
||||||
return ExprError();
|
return ExprError();
|
||||||
|
|
||||||
if (!E->getType().isPODType(Context)) {
|
if (!E->getType().isPODType(Context)) {
|
||||||
// C++0x [expr.call]p7:
|
// C++0x [expr.call]p7:
|
||||||
// Passing a potentially-evaluated argument of class type (Clause 9)
|
// Passing a potentially-evaluated argument of class type (Clause 9)
|
||||||
|
@ -519,16 +525,6 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT,
|
||||||
if (Comma.isInvalid())
|
if (Comma.isInvalid())
|
||||||
return ExprError();
|
return ExprError();
|
||||||
E = Comma.get();
|
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
|
// rdar://7309675
|
||||||
// PR4678
|
// 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
|
// CHECK: define i32 @_ZN5test05test1Ez(...)
|
||||||
// though there is no way to do a va_begin. Otherwise, the optimizer
|
int test1(...) {
|
||||||
// will warn about 'dropped arguments' at the call site.
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
// CHECK: define i32 @_Z5test1z(...)
|
// CHECK: call i32 (...)* @_ZN5test05test1Ez(i32 0)
|
||||||
int test1(...) {
|
void test() {
|
||||||
return -1;
|
test1(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// CHECK: call i32 (...)* @_Z5test1z(i32 0)
|
namespace test1 {
|
||||||
void test() {
|
struct A {
|
||||||
test1(0);
|
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