Rework our handling of binding a reference to a temporary
subobject. Previously, we could only properly bind to a base class
subobject while extending the lifetime of the complete object (of a
derived type); for non-static data member subobjects, we could memcpy
(!) the result and bind to that, which is rather broken.
Now, we pull apart the expression that we're binding to, to figure out
which subobject we're accessing, then construct the temporary object
(adding a destruction if needed) and, finally, dig out the subobject
we actually meant to access.
This fixes yet another instance where we were memcpy'ing rather than
doing the right thing. However, note the FIXME in references.cpp:
there's more work to be done for binding to subobjects, since the AST
is incorrectly modeling some member accesses in base classes as
lvalues when they are really rvalues.
llvm-svn: 104219
2010-05-20 16:36:28 +08:00
|
|
|
// RUN: %clang_cc1 -triple x86_64-apple-darwin -verify -emit-llvm -o - %s | FileCheck %s
|
2009-05-20 04:40:02 +08:00
|
|
|
void t1() {
|
|
|
|
extern int& a;
|
|
|
|
int b = a;
|
|
|
|
}
|
|
|
|
|
|
|
|
void t2(int& a) {
|
|
|
|
int b = a;
|
|
|
|
}
|
|
|
|
|
|
|
|
int g;
|
|
|
|
int& gr = g;
|
2009-05-27 14:04:58 +08:00
|
|
|
int& grr = gr;
|
2009-05-20 04:40:02 +08:00
|
|
|
void t3() {
|
|
|
|
int b = gr;
|
|
|
|
}
|
2009-05-20 08:36:58 +08:00
|
|
|
|
|
|
|
// Test reference binding.
|
|
|
|
|
2009-05-27 09:46:48 +08:00
|
|
|
struct C { int a; };
|
2009-05-20 09:03:17 +08:00
|
|
|
void f(const bool&);
|
2009-05-20 08:36:58 +08:00
|
|
|
void f(const int&);
|
|
|
|
void f(const _Complex int&);
|
|
|
|
void f(const C&);
|
|
|
|
|
2009-05-27 09:45:47 +08:00
|
|
|
C aggregate_return();
|
|
|
|
|
|
|
|
bool& bool_reference_return();
|
|
|
|
int& int_reference_return();
|
|
|
|
_Complex int& complex_int_reference_return();
|
2009-05-27 09:46:48 +08:00
|
|
|
C& aggregate_reference_return();
|
2009-05-20 10:31:19 +08:00
|
|
|
|
2009-05-20 09:03:17 +08:00
|
|
|
void test_bool() {
|
|
|
|
bool a = true;
|
|
|
|
f(a);
|
|
|
|
|
|
|
|
f(true);
|
2009-05-27 09:45:47 +08:00
|
|
|
|
|
|
|
bool_reference_return() = true;
|
2009-05-27 11:37:57 +08:00
|
|
|
a = bool_reference_return();
|
2010-02-04 03:13:55 +08:00
|
|
|
|
|
|
|
struct { const bool& b; } b = { true };
|
2009-05-20 09:03:17 +08:00
|
|
|
}
|
|
|
|
|
2009-05-20 08:36:58 +08:00
|
|
|
void test_scalar() {
|
|
|
|
int a = 10;
|
|
|
|
f(a);
|
2009-05-20 09:03:17 +08:00
|
|
|
|
2009-05-20 09:24:22 +08:00
|
|
|
struct { int bitfield : 3; } s = { 3 };
|
2009-05-20 09:27:39 +08:00
|
|
|
f(s.bitfield);
|
2009-05-20 09:24:22 +08:00
|
|
|
|
2009-05-20 09:03:17 +08:00
|
|
|
f(10);
|
2009-05-20 10:31:19 +08:00
|
|
|
|
|
|
|
__attribute((vector_size(16))) typedef int vec4;
|
|
|
|
f((vec4){1,2,3,4}[0]);
|
2009-05-27 09:45:47 +08:00
|
|
|
|
|
|
|
int_reference_return() = 10;
|
2009-05-27 11:37:57 +08:00
|
|
|
a = int_reference_return();
|
2010-02-04 03:13:55 +08:00
|
|
|
|
|
|
|
struct { const int& a; } agg = { 10 };
|
2009-05-20 08:36:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void test_complex() {
|
|
|
|
_Complex int a = 10i;
|
|
|
|
f(a);
|
2009-05-20 09:35:03 +08:00
|
|
|
|
|
|
|
f(10i);
|
2009-05-27 09:45:47 +08:00
|
|
|
|
|
|
|
complex_int_reference_return() = 10i;
|
2009-05-27 11:37:57 +08:00
|
|
|
a = complex_int_reference_return();
|
2010-02-04 03:13:55 +08:00
|
|
|
|
|
|
|
struct { const _Complex int &a; } agg = { 10i };
|
2009-05-20 08:36:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void test_aggregate() {
|
|
|
|
C c;
|
|
|
|
f(c);
|
2009-05-20 10:31:19 +08:00
|
|
|
|
2009-05-27 09:45:47 +08:00
|
|
|
f(aggregate_return());
|
2009-05-27 09:46:48 +08:00
|
|
|
aggregate_reference_return().a = 10;
|
2009-05-28 00:45:02 +08:00
|
|
|
|
|
|
|
c = aggregate_reference_return();
|
2010-02-04 03:13:55 +08:00
|
|
|
|
|
|
|
struct { const C& a; } agg = { C() };
|
2009-05-20 08:36:58 +08:00
|
|
|
}
|
|
|
|
|
2009-05-27 12:56:12 +08:00
|
|
|
int& reference_return() {
|
|
|
|
return g;
|
|
|
|
}
|
2009-05-27 13:39:06 +08:00
|
|
|
|
|
|
|
int reference_decl() {
|
|
|
|
int& a = g;
|
|
|
|
const int& b = 1;
|
|
|
|
return a+b;
|
|
|
|
}
|
2009-09-02 05:18:52 +08:00
|
|
|
|
|
|
|
struct A {
|
|
|
|
int& b();
|
|
|
|
};
|
|
|
|
|
|
|
|
void f(A* a) {
|
|
|
|
int b = a->b();
|
|
|
|
}
|
2009-10-04 00:30:22 +08:00
|
|
|
|
|
|
|
// PR5122
|
|
|
|
void *foo = 0;
|
|
|
|
void * const & kFoo = foo;
|
|
|
|
|
2009-10-15 08:51:46 +08:00
|
|
|
struct D : C { D(); ~D(); };
|
|
|
|
|
|
|
|
void h() {
|
|
|
|
// CHECK: call void @_ZN1DD1Ev
|
|
|
|
const C& c = D();
|
|
|
|
}
|
|
|
|
|
2009-10-19 07:09:21 +08:00
|
|
|
namespace T {
|
|
|
|
struct A {
|
|
|
|
A();
|
|
|
|
~A();
|
|
|
|
};
|
|
|
|
|
|
|
|
struct B {
|
|
|
|
B();
|
|
|
|
~B();
|
|
|
|
A f();
|
|
|
|
};
|
|
|
|
|
|
|
|
void f() {
|
|
|
|
// CHECK: call void @_ZN1T1BC1Ev
|
|
|
|
// CHECK: call void @_ZN1T1B1fEv
|
|
|
|
// CHECK: call void @_ZN1T1BD1Ev
|
|
|
|
const A& a = B().f();
|
|
|
|
// CHECK: call void @_ZN1T1fEv
|
|
|
|
f();
|
|
|
|
// CHECK: call void @_ZN1T1AD1Ev
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-10-20 02:28:22 +08:00
|
|
|
// PR5227.
|
|
|
|
namespace PR5227 {
|
|
|
|
void f(int &a) {
|
|
|
|
(a = 10) = 20;
|
|
|
|
}
|
|
|
|
}
|
2009-11-24 01:18:46 +08:00
|
|
|
|
|
|
|
// PR5590
|
|
|
|
struct s0;
|
|
|
|
struct s1 { struct s0 &s0; };
|
|
|
|
void f0(s1 a) { s1 b = a; }
|
2010-03-25 07:14:04 +08:00
|
|
|
|
|
|
|
// PR6024
|
|
|
|
// CHECK: @_Z2f2v()
|
Change IR generation for return (in the simple case) to avoid doing silly
load/store nonsense in the epilog. For example, for:
int foo(int X) {
int A[100];
return A[X];
}
we used to generate:
%arrayidx = getelementptr inbounds [100 x i32]* %A, i32 0, i64 %idxprom ; <i32*> [#uses=1]
%tmp1 = load i32* %arrayidx ; <i32> [#uses=1]
store i32 %tmp1, i32* %retval
%0 = load i32* %retval ; <i32> [#uses=1]
ret i32 %0
}
which codegen'd to this code:
_foo: ## @foo
## BB#0: ## %entry
subq $408, %rsp ## imm = 0x198
movl %edi, 400(%rsp)
movl 400(%rsp), %edi
movslq %edi, %rax
movl (%rsp,%rax,4), %edi
movl %edi, 404(%rsp)
movl 404(%rsp), %eax
addq $408, %rsp ## imm = 0x198
ret
Now we generate:
%arrayidx = getelementptr inbounds [100 x i32]* %A, i32 0, i64 %idxprom ; <i32*> [#uses=1]
%tmp1 = load i32* %arrayidx ; <i32> [#uses=1]
ret i32 %tmp1
}
and:
_foo: ## @foo
## BB#0: ## %entry
subq $408, %rsp ## imm = 0x198
movl %edi, 404(%rsp)
movl 404(%rsp), %edi
movslq %edi, %rax
movl (%rsp,%rax,4), %eax
addq $408, %rsp ## imm = 0x198
ret
This actually does matter, cutting out 2000 lines of IR from CGStmt.ll
for example.
Another interesting effect is that altivec.h functions which are dead
now get dce'd by the inliner. Hence all the changes to
builtins-ppc-altivec.c to ensure the calls aren't dead.
llvm-svn: 106970
2010-06-27 09:06:27 +08:00
|
|
|
// CHECK: alloca i32,
|
|
|
|
// CHECK-NEXT: store
|
|
|
|
// CHECK-NEXT: ret
|
2010-03-25 07:14:04 +08:00
|
|
|
const int &f2() { return 0; }
|
2010-05-16 17:32:51 +08:00
|
|
|
|
|
|
|
// Don't constant fold const reference parameters with default arguments to
|
|
|
|
// their default arguments.
|
|
|
|
namespace N1 {
|
|
|
|
const int foo = 1;
|
|
|
|
// CHECK: @_ZN2N14test
|
|
|
|
int test(const int& arg = foo) {
|
|
|
|
// Ensure this array is on the stack where we can set values instead of
|
|
|
|
// being a global constant.
|
|
|
|
// CHECK: %args_array = alloca
|
|
|
|
const int* const args_array[] = { &arg };
|
|
|
|
}
|
|
|
|
}
|
Rework our handling of binding a reference to a temporary
subobject. Previously, we could only properly bind to a base class
subobject while extending the lifetime of the complete object (of a
derived type); for non-static data member subobjects, we could memcpy
(!) the result and bind to that, which is rather broken.
Now, we pull apart the expression that we're binding to, to figure out
which subobject we're accessing, then construct the temporary object
(adding a destruction if needed) and, finally, dig out the subobject
we actually meant to access.
This fixes yet another instance where we were memcpy'ing rather than
doing the right thing. However, note the FIXME in references.cpp:
there's more work to be done for binding to subobjects, since the AST
is incorrectly modeling some member accesses in base classes as
lvalues when they are really rvalues.
llvm-svn: 104219
2010-05-20 16:36:28 +08:00
|
|
|
|
|
|
|
// Bind to subobjects while extending the life of the complete object.
|
|
|
|
namespace N2 {
|
|
|
|
class X {
|
|
|
|
public:
|
|
|
|
X(const X&);
|
|
|
|
X &operator=(const X&);
|
|
|
|
~X();
|
|
|
|
};
|
|
|
|
|
|
|
|
struct P {
|
|
|
|
X first;
|
|
|
|
};
|
|
|
|
|
|
|
|
P getP();
|
|
|
|
|
|
|
|
// CHECK: define void @_ZN2N21fEi
|
|
|
|
// CHECK: call void @_ZN2N24getPEv
|
|
|
|
// CHECK: getelementptr inbounds
|
|
|
|
// CHECK: store i32 17
|
|
|
|
// CHECK: call void @_ZN2N21PD1Ev
|
|
|
|
void f(int i) {
|
|
|
|
const X& xr = getP().first;
|
|
|
|
i = 17;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct SpaceWaster {
|
|
|
|
int i, j;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct ReallyHasX {
|
|
|
|
X x;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct HasX : ReallyHasX { };
|
|
|
|
|
|
|
|
struct HasXContainer {
|
|
|
|
HasX has;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Y : SpaceWaster, HasXContainer { };
|
|
|
|
struct Z : SpaceWaster, Y { };
|
|
|
|
|
|
|
|
Z getZ();
|
|
|
|
|
|
|
|
// CHECK: define void @_ZN2N21gEi
|
|
|
|
// CHECK: call void @_ZN2N24getZEv
|
2010-05-22 13:17:18 +08:00
|
|
|
// CHECK: {{getelementptr inbounds.*i32 0, i32 0}}
|
|
|
|
// CHECK: {{getelementptr inbounds.*i32 0, i32 0}}
|
|
|
|
// CHECK: store i32 19
|
|
|
|
// CHECK: call void @_ZN2N21ZD1Ev
|
|
|
|
// CHECK: ret void
|
Rework our handling of binding a reference to a temporary
subobject. Previously, we could only properly bind to a base class
subobject while extending the lifetime of the complete object (of a
derived type); for non-static data member subobjects, we could memcpy
(!) the result and bind to that, which is rather broken.
Now, we pull apart the expression that we're binding to, to figure out
which subobject we're accessing, then construct the temporary object
(adding a destruction if needed) and, finally, dig out the subobject
we actually meant to access.
This fixes yet another instance where we were memcpy'ing rather than
doing the right thing. However, note the FIXME in references.cpp:
there's more work to be done for binding to subobjects, since the AST
is incorrectly modeling some member accesses in base classes as
lvalues when they are really rvalues.
llvm-svn: 104219
2010-05-20 16:36:28 +08:00
|
|
|
void g(int i) {
|
|
|
|
const X &xr = getZ().has.x;
|
|
|
|
i = 19;
|
|
|
|
}
|
|
|
|
}
|