mirror of
https://github.com/llvm/llvm-project.git
synced 2025-05-17 00:46:05 +00:00

poor (and wrong) approximation of the actual rules governing when to build a copy and when it can be elided. The correct implementation is actually simpler than the approximation. When we only enumerate constructors as part of initialization (e.g., for direct initialization or when we're copying from a class type or one of its derived classes), we don't create a copy. When we enumerate all conversion functions, we do create a copy. Before, we created some extra copies and missed some others. The new test copy-initialization.cpp shows a case where we missed creating a (required, non-elidable) copy as part of a user-defined conversion, which resulted in a miscompile. This commit also fixes PR6757, where the missing copy made us reject well-formed code in the ternary operator. This commit also cleans up our handling of copy elision in the case where we create an extra copy of a temporary object, which became necessary now that we produce the right copies. The code that seeks to find the temporary object being copied has moved into Expr::getTemporaryObject(); it used to have two different not-quite-the-same implementations, one in Sema and one in CodeGen. Note that we still do not attempt to perform the named return value optimization, so we miss copy elisions for return values and throw expressions. llvm-svn: 100196
85 lines
1.6 KiB
C++
85 lines
1.6 KiB
C++
// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++0x -S %s -o %t-64.s
|
|
// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
|
|
// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++0x -S %s -o %t-32.s
|
|
// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s
|
|
|
|
extern "C" int printf(...);
|
|
extern "C" void exit(int);
|
|
|
|
struct A {
|
|
A (const A&) { printf("A::A(const A&)\n"); }
|
|
A() {};
|
|
~A() { printf("A::~A()\n"); }
|
|
};
|
|
|
|
struct B : public A {
|
|
B() {};
|
|
B(const B& Other) : A(Other) { printf("B::B(const B&)\n"); }
|
|
~B() { printf("B::~B()\n"); }
|
|
};
|
|
|
|
struct C : public B {
|
|
C() {};
|
|
C(const C& Other) : B(Other) { printf("C::C(const C&)\n"); }
|
|
~C() { printf("C::~C()\n"); }
|
|
};
|
|
|
|
struct X {
|
|
operator B&() {printf("X::operator B&()\n"); return b; }
|
|
operator C&() {printf("X::operator C&()\n"); return c; }
|
|
X (const X&) { printf("X::X(const X&)\n"); }
|
|
X () { printf("X::X()\n"); }
|
|
~X () { printf("X::~X()\n"); }
|
|
B b;
|
|
C c;
|
|
};
|
|
|
|
void f(A) {
|
|
printf("f(A)\n");
|
|
}
|
|
|
|
|
|
void func(X x)
|
|
{
|
|
f (x);
|
|
}
|
|
|
|
int main()
|
|
{
|
|
X x;
|
|
func(x);
|
|
}
|
|
|
|
struct Base;
|
|
|
|
struct Root {
|
|
operator Base&() { exit(1); }
|
|
};
|
|
|
|
struct Derived;
|
|
|
|
struct Base : Root {
|
|
Base(const Base&) { printf("Base::(const Base&)\n"); }
|
|
Base() { printf("Base::Base()\n"); }
|
|
operator Derived&() { exit(1); }
|
|
};
|
|
|
|
struct Derived : Base {
|
|
};
|
|
|
|
void foo(Base) {}
|
|
|
|
void test(Derived bb)
|
|
{
|
|
// CHECK-LP64-NOT: callq __ZN4BasecvR7DerivedEv
|
|
// CHECK-LP32-NOT: callq L__ZN4BasecvR7DerivedEv
|
|
foo(bb);
|
|
}
|
|
// CHECK-LP64: callq __ZN1XcvR1BEv
|
|
// CHECK-LP64: callq __ZN1AC1ERKS_
|
|
|
|
// CHECK-LP32: call L__ZN1XcvR1BEv
|
|
// CHECK-LP32: call L__ZN1AC1ERKS_
|
|
|
|
|