diff options
author | Douglas Gregor <dgregor@apple.com> | 2010-04-02 18:24:57 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2010-04-02 18:24:57 +0000 |
commit | 45cf7e3d2a524e751c2d5c35f2761a8cfbc47fdd (patch) | |
tree | 758fe66ff8493c68ce04d93ab2ca1c9709f311b2 /clang/test | |
parent | 4b82a8876434e76921f15f4b395440179515b7b5 (diff) | |
download | bcm5719-llvm-45cf7e3d2a524e751c2d5c35f2761a8cfbc47fdd.tar.gz bcm5719-llvm-45cf7e3d2a524e751c2d5c35f2761a8cfbc47fdd.zip |
Rework our handling of copy construction of temporaries, which was a
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
Diffstat (limited to 'clang/test')
-rw-r--r-- | clang/test/CodeGenCXX/copy-initialization.cpp | 29 | ||||
-rw-r--r-- | clang/test/CodeGenCXX/derived-to-base-conv.cpp | 12 | ||||
-rw-r--r-- | clang/test/CodeGenCXX/virt.cpp | 2 | ||||
-rw-r--r-- | clang/test/SemaCXX/conditional-expr.cpp | 27 | ||||
-rw-r--r-- | clang/test/SemaCXX/copy-initialization.cpp | 20 |
5 files changed, 86 insertions, 4 deletions
diff --git a/clang/test/CodeGenCXX/copy-initialization.cpp b/clang/test/CodeGenCXX/copy-initialization.cpp new file mode 100644 index 00000000000..62b9f2678a4 --- /dev/null +++ b/clang/test/CodeGenCXX/copy-initialization.cpp @@ -0,0 +1,29 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s + +struct Foo { + Foo(); + Foo(const Foo&); +}; + +struct Bar { + Bar(); + operator const Foo&() const; +}; + +void f(Foo); + +// CHECK: define void @_Z1g3Foo(%struct.Bar* %foo) +void g(Foo foo) { + // CHECK: call void @_ZN3BarC1Ev + // CHECK: @_ZNK3BarcvRK3FooEv + // CHECK: call void @_Z1f3Foo + f(Bar()); + // CHECK: call void @_ZN3FooC1Ev + // CHECK: call void @_Z1f3Foo + f(Foo()); + // CHECK: call void @_ZN3FooC1ERKS_ + // CHECK: call void @_Z1f3Foo + f(foo); + // CHECK: ret +} + diff --git a/clang/test/CodeGenCXX/derived-to-base-conv.cpp b/clang/test/CodeGenCXX/derived-to-base-conv.cpp index c1a0caa7584..f2835b7a299 100644 --- a/clang/test/CodeGenCXX/derived-to-base-conv.cpp +++ b/clang/test/CodeGenCXX/derived-to-base-conv.cpp @@ -7,16 +7,21 @@ extern "C" int printf(...); extern "C" void exit(int); struct A { - A (const A&) { printf("A::A(const A&)\n"); } - 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 { @@ -24,6 +29,7 @@ struct X { 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; }; diff --git a/clang/test/CodeGenCXX/virt.cpp b/clang/test/CodeGenCXX/virt.cpp index c4041296309..326d3227305 100644 --- a/clang/test/CodeGenCXX/virt.cpp +++ b/clang/test/CodeGenCXX/virt.cpp @@ -104,7 +104,7 @@ struct test7_B1 : virtual test7_B2 { virtual void funcB1(); }; struct test7_D : test7_B2, virtual test7_B1 { }; -// CHECK-LP64: .zerofill __DATA,__common,_d7,16,3 +// CHECK-LP64: .zerofill __DATA,__common,_d7,16,4 struct test3_B3 { virtual void funcB3(); }; diff --git a/clang/test/SemaCXX/conditional-expr.cpp b/clang/test/SemaCXX/conditional-expr.cpp index e2a966bdd95..49bcd99fb69 100644 --- a/clang/test/SemaCXX/conditional-expr.cpp +++ b/clang/test/SemaCXX/conditional-expr.cpp @@ -213,3 +213,30 @@ namespace PR6595 { (void)(Cond? a : S); } } + +namespace PR6757 { + struct Foo1 { + Foo1(); + Foo1(const Foo1&); + }; + + struct Foo2 { }; + + struct Foo3 { + Foo3(); + Foo3(Foo3&); + }; + + struct Bar { + operator const Foo1&() const; + operator const Foo2&() const; + operator const Foo3&() const; + }; + + void f() { + (void)(true ? Bar() : Foo1()); // okay + (void)(true ? Bar() : Foo2()); // okay + // FIXME: Diagnostic below could be improved + (void)(true ? Bar() : Foo3()); // expected-error{{incompatible operand types ('PR6757::Bar' and 'PR6757::Foo3')}} + } +} diff --git a/clang/test/SemaCXX/copy-initialization.cpp b/clang/test/SemaCXX/copy-initialization.cpp index 3a63be0970d..e5b1fd766bb 100644 --- a/clang/test/SemaCXX/copy-initialization.cpp +++ b/clang/test/SemaCXX/copy-initialization.cpp @@ -21,3 +21,23 @@ struct foo { // PR3600 void test(const foo *P) { P->bar(); } // expected-error{{cannot initialize object parameter of type 'foo' with an expression of type 'foo const'}} + +namespace PR6757 { + struct Foo { + Foo(); + Foo(Foo&); + }; + + struct Bar { + operator const Foo&() const; + }; + + void f(Foo); // expected-note{{candidate function not viable: no known conversion from 'PR6757::Bar' to 'PR6757::Foo' for 1st argument}} + + // FIXME: This isn't really the right reason for the failure. We + // should fail after overload resolution. + void g(Foo foo) { + f(Bar()); // expected-error{{no matching function for call to 'f'}} + f(foo); + } +} |