[cfe-commits] r100196 - in /cfe/trunk: include/clang/AST/Expr.h lib/AST/Expr.cpp lib/CodeGen/CGExprCXX.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaInit.cpp test/CodeGenCXX/copy-initialization.cpp test/CodeGenCXX/derived-to-base-conv.cpp test/CodeGenCXX/virt.cpp test/SemaCXX/conditional-expr.cpp test/SemaCXX/copy-initialization.cpp

Douglas Gregor dgregor at apple.com
Fri Apr 2 11:24:57 PDT 2010


Author: dgregor
Date: Fri Apr  2 13:24:57 2010
New Revision: 100196

URL: http://llvm.org/viewvc/llvm-project?rev=100196&view=rev
Log:
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.


Added:
    cfe/trunk/test/CodeGenCXX/copy-initialization.cpp   (with props)
Modified:
    cfe/trunk/include/clang/AST/Expr.h
    cfe/trunk/lib/AST/Expr.cpp
    cfe/trunk/lib/CodeGen/CGExprCXX.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaInit.cpp
    cfe/trunk/test/CodeGenCXX/derived-to-base-conv.cpp
    cfe/trunk/test/CodeGenCXX/virt.cpp
    cfe/trunk/test/SemaCXX/conditional-expr.cpp
    cfe/trunk/test/SemaCXX/copy-initialization.cpp

Modified: cfe/trunk/include/clang/AST/Expr.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=100196&r1=100195&r2=100196&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Expr.h (original)
+++ cfe/trunk/include/clang/AST/Expr.h Fri Apr  2 13:24:57 2010
@@ -322,6 +322,15 @@
   /// the expression is a default argument.
   bool isDefaultArgument() const;
   
+  /// \brief Determine whether this expression directly creates a
+  /// temporary object (of class type).
+  bool isTemporaryObject() const { return getTemporaryObject() != 0; }
+
+  /// \brief If this expression directly creates a temporary object of
+  /// class type, return the expression that actually constructs that
+  /// temporary object.
+  const Expr *getTemporaryObject() const;
+
   const Expr* IgnoreParens() const {
     return const_cast<Expr*>(this)->IgnoreParens();
   }

Modified: cfe/trunk/lib/AST/Expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=100196&r1=100195&r2=100196&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Expr.cpp (original)
+++ cfe/trunk/lib/AST/Expr.cpp Fri Apr  2 13:24:57 2010
@@ -1476,6 +1476,71 @@
   return isa<CXXDefaultArgExpr>(E);
 }
 
+/// \brief Skip over any no-op casts and any temporary-binding
+/// expressions.
+static const Expr *skipTemporaryBindingsAndNoOpCasts(const Expr *E) {
+  while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
+    if (ICE->getCastKind() == CastExpr::CK_NoOp)
+      E = ICE->getSubExpr();
+    else
+      break;
+  }
+
+  while (const CXXBindTemporaryExpr *BE = dyn_cast<CXXBindTemporaryExpr>(E))
+    E = BE->getSubExpr();
+
+  while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
+    if (ICE->getCastKind() == CastExpr::CK_NoOp)
+      E = ICE->getSubExpr();
+    else
+      break;
+  }
+  
+  return E;
+}
+
+const Expr *Expr::getTemporaryObject() const {
+  const Expr *E = skipTemporaryBindingsAndNoOpCasts(this);
+
+  // A cast can produce a temporary object. The object's construction
+  // is represented as a CXXConstructExpr.
+  if (const CastExpr *Cast = dyn_cast<CastExpr>(E)) {
+    // Only user-defined and constructor conversions can produce
+    // temporary objects.
+    if (Cast->getCastKind() != CastExpr::CK_ConstructorConversion &&
+        Cast->getCastKind() != CastExpr::CK_UserDefinedConversion)
+      return 0;
+
+    // Strip off temporary bindings and no-op casts.
+    const Expr *Sub = skipTemporaryBindingsAndNoOpCasts(Cast->getSubExpr());
+
+    // If this is a constructor conversion, see if we have an object
+    // construction.
+    if (Cast->getCastKind() == CastExpr::CK_ConstructorConversion)
+      return dyn_cast<CXXConstructExpr>(Sub);
+
+    // If this is a user-defined conversion, see if we have a call to
+    // a function that itself returns a temporary object.
+    if (Cast->getCastKind() == CastExpr::CK_UserDefinedConversion)
+      if (const CallExpr *CE = dyn_cast<CallExpr>(Sub))
+        if (CE->getCallReturnType()->isRecordType())
+          return CE;
+
+    return 0;
+  }
+
+  // A call returning a class type returns a temporary.
+  if (const CallExpr *CE = dyn_cast<CallExpr>(E)) {
+    if (CE->getCallReturnType()->isRecordType())
+      return CE;
+
+    return 0;
+  }
+
+  // Explicit temporary object constructors create temporaries.
+  return dyn_cast<CXXTemporaryObjectExpr>(E);
+}
+
 /// hasAnyTypeDependentArguments - Determines if any of the expressions
 /// in Exprs is type-dependent.
 bool Expr::hasAnyTypeDependentArguments(Expr** Exprs, unsigned NumExprs) {

Modified: cfe/trunk/lib/CodeGen/CGExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprCXX.cpp?rev=100196&r1=100195&r2=100196&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprCXX.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprCXX.cpp Fri Apr  2 13:24:57 2010
@@ -307,23 +307,7 @@
   // Code gen optimization to eliminate copy constructor and return
   // its first argument instead.
   if (getContext().getLangOptions().ElideConstructors && E->isElidable()) {
-    const Expr *Arg = E->getArg(0);
-    
-    if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) {
-      assert((ICE->getCastKind() == CastExpr::CK_NoOp ||
-              ICE->getCastKind() == CastExpr::CK_ConstructorConversion ||
-              ICE->getCastKind() == CastExpr::CK_UserDefinedConversion) &&
-             "Unknown implicit cast kind in constructor elision");
-      Arg = ICE->getSubExpr();
-    }
-    
-    if (const CXXFunctionalCastExpr *FCE = dyn_cast<CXXFunctionalCastExpr>(Arg))
-      Arg = FCE->getSubExpr();
-    
-    if (const CXXBindTemporaryExpr *BindExpr = 
-        dyn_cast<CXXBindTemporaryExpr>(Arg))
-      Arg = BindExpr->getSubExpr();
-    
+    const Expr *Arg = E->getArg(0)->getTemporaryObject();
     EmitAggExpr(Arg, Dest, false);
     return;
   }

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=100196&r1=100195&r2=100196&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Fri Apr  2 13:24:57 2010
@@ -3965,33 +3965,21 @@
                             bool BaseInitialization) {
   bool Elidable = false;
 
-  // C++ [class.copy]p15:
-  //   Whenever a temporary class object is copied using a copy constructor, and
-  //   this object and the copy have the same cv-unqualified type, an
-  //   implementation is permitted to treat the original and the copy as two
-  //   different ways of referring to the same object and not perform a copy at
-  //   all, even if the class copy constructor or destructor have side effects.
-
-  // FIXME: Is this enough?
-  if (Constructor->isCopyConstructor()) {
-    Expr *E = ((Expr **)ExprArgs.get())[0];
-    if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E))
-      if (ICE->getCastKind() == CastExpr::CK_NoOp)
-        E = ICE->getSubExpr();
-    if (CXXFunctionalCastExpr *FCE = dyn_cast<CXXFunctionalCastExpr>(E))
-      E = FCE->getSubExpr();
-    while (CXXBindTemporaryExpr *BE = dyn_cast<CXXBindTemporaryExpr>(E))
-      E = BE->getSubExpr();
-    if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E))
-      if (ICE->getCastKind() == CastExpr::CK_NoOp)
-        E = ICE->getSubExpr();
-
-    if (CallExpr *CE = dyn_cast<CallExpr>(E))
-      Elidable = !CE->getCallReturnType()->isReferenceType();
-    else if (isa<CXXTemporaryObjectExpr>(E))
-      Elidable = true;
-    else if (isa<CXXConstructExpr>(E))
-      Elidable = true;
+  // C++0x [class.copy]p34:
+  //   When certain criteria are met, an implementation is allowed to
+  //   omit the copy/move construction of a class object, even if the
+  //   copy/move constructor and/or destructor for the object have
+  //   side effects. [...]
+  //     - when a temporary class object that has not been bound to a
+  //       reference (12.2) would be copied/moved to a class object
+  //       with the same cv-unqualified type, the copy/move operation
+  //       can be omitted by constructing the temporary object
+  //       directly into the target of the omitted copy/move
+  if (Constructor->isCopyConstructor() && ExprArgs.size() >= 1) {
+    Expr *SubExpr = ((Expr **)ExprArgs.get())[0];
+    Elidable = SubExpr->isTemporaryObject() &&
+      Context.hasSameUnqualifiedType(SubExpr->getType(), 
+                           Context.getTypeDeclType(Constructor->getParent()));
   }
 
   return BuildCXXConstructExpr(ConstructLoc, DeclInitType, Constructor,

Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=100196&r1=100195&r2=100196&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Fri Apr  2 13:24:57 2010
@@ -2583,10 +2583,7 @@
                                          Expr **Args, unsigned NumArgs,
                                          QualType DestType,
                                          InitializationSequence &Sequence) {
-  if (Kind.getKind() == InitializationKind::IK_Copy)
-    Sequence.setSequenceKind(InitializationSequence::UserDefinedConversion);
-  else
-    Sequence.setSequenceKind(InitializationSequence::ConstructorInitialization);
+  Sequence.setSequenceKind(InitializationSequence::ConstructorInitialization);
   
   // Build the candidate set directly in the initialization sequence
   // structure, so that it will persist if we fail.
@@ -2597,7 +2594,7 @@
   // explicit conversion operators.
   bool AllowExplicit = (Kind.getKind() == InitializationKind::IK_Direct ||
                         Kind.getKind() == InitializationKind::IK_Value ||
-                        Kind.getKind() == InitializationKind::IK_Default);                      
+                        Kind.getKind() == InitializationKind::IK_Default);
   
   // The type we're converting to is a class type. Enumerate its constructors
   // to see if one is suitable.
@@ -2661,14 +2658,10 @@
 
   // Add the constructor initialization step. Any cv-qualification conversion is
   // subsumed by the initialization.
-  if (Kind.getKind() == InitializationKind::IK_Copy) {
-    Sequence.AddUserConversionStep(Best->Function, Best->FoundDecl, DestType);
-  } else {
-    Sequence.AddConstructorInitializationStep(
+  Sequence.AddConstructorInitializationStep(
                                       cast<CXXConstructorDecl>(Best->Function), 
                                       Best->FoundDecl.getAccess(),
                                       DestType);
-  }
 }
 
 /// \brief Attempt value initialization (C++ [dcl.init]p7).
@@ -3085,14 +3078,11 @@
   return Sema::AA_Converting;
 }
 
-static bool shouldBindAsTemporary(const InitializedEntity &Entity,
-                                  bool IsCopy) {
+static bool shouldBindAsTemporary(const InitializedEntity &Entity) {
   switch (Entity.getKind()) {
-  case InitializedEntity::EK_Result:
   case InitializedEntity::EK_ArrayElement:
   case InitializedEntity::EK_Member:
-    return !IsCopy;
-      
+  case InitializedEntity::EK_Result:
   case InitializedEntity::EK_New:
   case InitializedEntity::EK_Variable:
   case InitializedEntity::EK_Base:
@@ -3108,21 +3098,38 @@
   llvm_unreachable("missed an InitializedEntity kind?");
 }
 
-/// \brief If we need to perform an additional copy of the initialized object
-/// for this kind of entity (e.g., the result of a function or an object being
-/// thrown), make the copy. 
-static Sema::OwningExprResult CopyIfRequiredForEntity(Sema &S,
-                                            const InitializedEntity &Entity,
-                                             const InitializationKind &Kind,
-                                             Sema::OwningExprResult CurInit) {
+static Sema::OwningExprResult CopyObject(Sema &S,
+                                         const InitializedEntity &Entity,
+                                         const InitializationKind &Kind,
+                                         Sema::OwningExprResult CurInit) {
+  // Determine which class type we're copying.
   Expr *CurInitExpr = (Expr *)CurInit.get();
-  
+  CXXRecordDecl *Class = 0; 
+  if (const RecordType *Record = CurInitExpr->getType()->getAs<RecordType>())
+    Class = cast<CXXRecordDecl>(Record->getDecl());
+  if (!Class)
+    return move(CurInit);
+
+  // C++0x [class.copy]p34:
+  //   When certain criteria are met, an implementation is allowed to
+  //   omit the copy/move construction of a class object, even if the
+  //   copy/move constructor and/or destructor for the object have
+  //   side effects. [...]
+  //     - when a temporary class object that has not been bound to a
+  //       reference (12.2) would be copied/moved to a class object
+  //       with the same cv-unqualified type, the copy/move operation
+  //       can be omitted by constructing the temporary object
+  //       directly into the target of the omitted copy/move
+  // 
+  // Note that the other three bullets are handled elsewhere. Copy
+  // elision for return statements and throw expressions are (FIXME:
+  // not yet) handled as part of constructor initialization, while
+  // copy elision for exception handlers is handled by the run-time.
+  bool Elidable = CurInitExpr->isTemporaryObject() &&
+    S.Context.hasSameUnqualifiedType(Entity.getType(), CurInitExpr->getType());
   SourceLocation Loc;
-  
   switch (Entity.getKind()) {
   case InitializedEntity::EK_Result:
-    if (Entity.getType()->isReferenceType())
-      return move(CurInit);
     Loc = Entity.getReturnLoc();
     break;
       
@@ -3131,38 +3138,20 @@
     break;
     
   case InitializedEntity::EK_Variable:
-    if (Entity.getType()->isReferenceType() ||
-        Kind.getKind() != InitializationKind::IK_Copy)
-      return move(CurInit);
     Loc = Entity.getDecl()->getLocation();
     break;
 
   case InitializedEntity::EK_ArrayElement:
   case InitializedEntity::EK_Member:
-    if (Entity.getType()->isReferenceType() ||
-        Kind.getKind() != InitializationKind::IK_Copy)
-      return move(CurInit);
-    Loc = CurInitExpr->getLocStart();
-    break;
-
   case InitializedEntity::EK_Parameter:
-    // FIXME: Do we need this initialization for a parameter?
-    return move(CurInit);
-
-  case InitializedEntity::EK_New:
   case InitializedEntity::EK_Temporary:
+  case InitializedEntity::EK_New:
   case InitializedEntity::EK_Base:
   case InitializedEntity::EK_VectorElement:
-    // We don't need to copy for any of these initialized entities.
-    return move(CurInit);
+    Loc = CurInitExpr->getLocStart();
+    break;
   }
-  
-  CXXRecordDecl *Class = 0; 
-  if (const RecordType *Record = CurInitExpr->getType()->getAs<RecordType>())
-    Class = cast<CXXRecordDecl>(Record->getDecl());
-  if (!Class)
-    return move(CurInit);
-  
+    
   // Perform overload resolution using the class's copy constructors.
   DeclarationName ConstructorName
     = S.Context.DeclarationNames.getCXXConstructorName(
@@ -3171,7 +3160,7 @@
   OverloadCandidateSet CandidateSet(Loc);
   for (llvm::tie(Con, ConEnd) = Class->lookup(ConstructorName);
        Con != ConEnd; ++Con) {
-    // Find the constructor (which may be a template).
+    // Only consider copy constructors.
     CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(*Con);
     if (!Constructor || Constructor->isInvalidDecl() ||
         !Constructor->isCopyConstructor())
@@ -3181,7 +3170,7 @@
       = DeclAccessPair::make(Constructor, Constructor->getAccess());
     S.AddOverloadCandidate(Constructor, FoundDecl,
                            &CurInitExpr, 1, CandidateSet);
-  }    
+  }
   
   OverloadCandidateSet::iterator Best;
   switch (S.BestViableFunction(CandidateSet, Loc, Best)) {
@@ -3218,9 +3207,9 @@
                            Best->FoundDecl.getAccess());
 
   CurInit.release();
-  return S.BuildCXXConstructExpr(Loc, CurInitExpr->getType(),
+  return S.BuildCXXConstructExpr(Loc, Entity.getType().getNonReferenceType(),
                                  cast<CXXConstructorDecl>(Best->Function),
-                                 /*Elidable=*/true,
+                                 Elidable,
                                  Sema::MultiExprArg(S, 
                                                     (void**)&CurInitExpr, 1));
 }
@@ -3474,7 +3463,9 @@
         CastKind = CastExpr::CK_UserDefinedConversion;
       }
       
-      if (shouldBindAsTemporary(Entity, IsCopy))
+      bool RequiresCopy = !IsCopy && 
+        getKind() != InitializationSequence::ReferenceBinding;
+      if (RequiresCopy || shouldBindAsTemporary(Entity))
         CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>());
 
       CurInitExpr = CurInit.takeAs<Expr>();
@@ -3483,8 +3474,8 @@
                                                          CurInitExpr,
                                                          IsLvalue));
       
-      if (!IsCopy)
-        CurInit = CopyIfRequiredForEntity(S, Entity, Kind, move(CurInit));
+      if (RequiresCopy)
+        CurInit = CopyObject(S, Entity, Kind, move(CurInit));
       break;
     }
         
@@ -3560,13 +3551,9 @@
       S.CheckConstructorAccess(Loc, Constructor,
                                Step->Function.FoundDecl.getAccess());
       
-      bool Elidable 
-        = cast<CXXConstructExpr>((Expr *)CurInit.get())->isElidable();
-      if (shouldBindAsTemporary(Entity, Elidable))
+      if (shouldBindAsTemporary(Entity))
         CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>());
-      
-      if (!Elidable)
-        CurInit = CopyIfRequiredForEntity(S, Entity, Kind, move(CurInit));
+
       break;
     }
         

Added: cfe/trunk/test/CodeGenCXX/copy-initialization.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/copy-initialization.cpp?rev=100196&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/copy-initialization.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/copy-initialization.cpp Fri Apr  2 13:24:57 2010
@@ -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
+}
+

Propchange: cfe/trunk/test/CodeGenCXX/copy-initialization.cpp
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/CodeGenCXX/copy-initialization.cpp
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/CodeGenCXX/copy-initialization.cpp
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: cfe/trunk/test/CodeGenCXX/derived-to-base-conv.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/derived-to-base-conv.cpp?rev=100196&r1=100195&r2=100196&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/derived-to-base-conv.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/derived-to-base-conv.cpp Fri Apr  2 13:24:57 2010
@@ -7,16 +7,21 @@
 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 @@
 	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;
 };

Modified: cfe/trunk/test/CodeGenCXX/virt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/virt.cpp?rev=100196&r1=100195&r2=100196&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/virt.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/virt.cpp Fri Apr  2 13:24:57 2010
@@ -104,7 +104,7 @@
 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(); };

Modified: cfe/trunk/test/SemaCXX/conditional-expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/conditional-expr.cpp?rev=100196&r1=100195&r2=100196&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/conditional-expr.cpp (original)
+++ cfe/trunk/test/SemaCXX/conditional-expr.cpp Fri Apr  2 13:24:57 2010
@@ -213,3 +213,30 @@
     (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')}}
+  }
+}

Modified: cfe/trunk/test/SemaCXX/copy-initialization.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/copy-initialization.cpp?rev=100196&r1=100195&r2=100196&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/copy-initialization.cpp (original)
+++ cfe/trunk/test/SemaCXX/copy-initialization.cpp Fri Apr  2 13:24:57 2010
@@ -21,3 +21,23 @@
 
 // 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);
+  }
+}





More information about the cfe-commits mailing list