[cfe-commits] r91669 - in /cfe/trunk: include/clang/Basic/ lib/CodeGen/ lib/Sema/ test/CXX/dcl.decl/dcl.init/dcl.init.ref/ test/CXX/temp/temp.decls/temp.class/temp.static/ test/CodeGenCXX/ test/SemaCXX/ test/SemaTemplate/

Douglas Gregor dgregor at apple.com
Thu Dec 17 21:02:25 PST 2009


Author: dgregor
Date: Thu Dec 17 23:02:21 2009
New Revision: 91669

URL: http://llvm.org/viewvc/llvm-project?rev=91669&view=rev
Log:
Switch the initialization required by return statements over to the
new InitializationSequence. This fixes some bugs (e.g., PR5808),
changed some diagnostics, and caused more churn than expected. What's
new:

  - InitializationSequence now has a "C conversion sequence" category
    and step kind, which falls back to
  - Changed the diagnostics for returns to always have the result type
    of the function first and the type of the expression second.
    CheckSingleAssignmentConstraints to peform checking in C. 
  - Improved ASTs for initialization of return values. The ASTs now
    capture all of the temporaries we need to create, but
    intentionally do not bind the tempoary that is actually returned,
    so that it won't get destroyed twice.
  - Make sure to perform an (elidable!) copy of the class object that
    is returned from a class.
  - Fix copy elision in CodeGen to properly see through the
    subexpressions that occur with elidable copies.
  - Give "new" its own entity kind; as with return values and thrown
    objects, we don't bind the expression so we don't call a
    destructor for it.

Note that, with this patch, I've broken returning move-only types in
C++0x. We'll fix it later, when we tackle NRVO.


Added:
    cfe/trunk/test/SemaCXX/rval-references-xfail.cpp   (with props)
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/CodeGen/CGCXX.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaExprCXX.cpp
    cfe/trunk/lib/Sema/SemaInit.cpp
    cfe/trunk/lib/Sema/SemaInit.h
    cfe/trunk/lib/Sema/SemaStmt.cpp
    cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-var.cpp
    cfe/trunk/test/CXX/temp/temp.decls/temp.class/temp.static/p1.cpp
    cfe/trunk/test/CodeGenCXX/temporaries.cpp
    cfe/trunk/test/SemaCXX/conversion-function.cpp
    cfe/trunk/test/SemaCXX/decl-init-ref.cpp
    cfe/trunk/test/SemaCXX/ref-init-ambiguous.cpp
    cfe/trunk/test/SemaCXX/rval-references.cpp
    cfe/trunk/test/SemaTemplate/class-template-id.cpp
    cfe/trunk/test/SemaTemplate/constructor-template.cpp
    cfe/trunk/test/SemaTemplate/instantiate-expr-4.cpp
    cfe/trunk/test/SemaTemplate/instantiate-function-1.cpp
    cfe/trunk/test/SemaTemplate/instantiate-member-template.cpp
    cfe/trunk/test/SemaTemplate/instantiate-typedef.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=91669&r1=91668&r2=91669&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Dec 17 23:02:21 2009
@@ -527,6 +527,11 @@
   "expected the class name after '~' to name the enclosing class">;
 
 // C++ initialization
+def err_init_conversion_failed : Error<
+  "cannot initialize %select{a variable|a parameter|return object|an "
+  "exception object|a value|a base class|a member subobject|an array element}0"
+  " of type %1 with an %select{rvalue|lvalue}2 of type %3">;
+
 def err_lvalue_to_rvalue_ref : Error<"rvalue reference cannot bind to lvalue">;
 def err_invalid_initialization : Error<
 "invalid initialization of reference of type %0 from expression of type %1">;
@@ -572,6 +577,16 @@
 def warn_field_is_uninit : Warning<"field is uninitialized when used here">,
   InGroup<DiagGroup<"uninitialized">>;
 
+def err_temp_copy_no_viable : Error<
+  "no viable copy constructor %select{throwing|returning}0 object of type %1">;
+def err_temp_copy_ambiguous : Error<
+  "ambiguous copy constructor call when %select{throwing|returning}0 object of "
+  "type %1">;
+def err_temp_copy_deleted : Error<
+  "%select{throwing|returning}0 object of type %1 invokes deleted copy "
+  "constructor">;
+  
+  
 // C++0x decltype
 def err_cannot_determine_declared_type_of_overloaded_function : Error<
     "can't determine the declared type of an overloaded function">;

Modified: cfe/trunk/lib/CodeGen/CGCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXX.cpp?rev=91669&r1=91668&r2=91669&view=diff

==============================================================================
--- cfe/trunk/lib/CodeGen/CGCXX.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGCXX.cpp Thu Dec 17 23:02:21 2009
@@ -577,9 +577,12 @@
   // its first argument instead.
   if (getContext().getLangOptions().ElideConstructors && E->isElidable()) {
     const Expr *Arg = E->getArg(0);
-    
-    if (const CXXBindTemporaryExpr *BindExpr = 
-          dyn_cast<CXXBindTemporaryExpr>(Arg))
+
+    if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) {
+      if (isa<CXXBindTemporaryExpr>(ICE->getSubExpr()))
+        Arg = cast<CXXBindTemporaryExpr>(ICE->getSubExpr())->getSubExpr();
+    } else if (const CXXBindTemporaryExpr *BindExpr = 
+                  dyn_cast<CXXBindTemporaryExpr>(Arg))
       Arg = BindExpr->getSubExpr();
 
     EmitAggExpr(Arg, Dest, false);

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=91669&r1=91668&r2=91669&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Thu Dec 17 23:02:21 2009
@@ -935,6 +935,9 @@
   bool PerformCopyInitialization(Expr *&From, QualType ToType,
                                  AssignmentAction Action, bool Elidable = false);
 
+  OwningExprResult PerformCopyInitialization(const InitializedEntity &Entity,
+                                             SourceLocation EqualLoc,
+                                             OwningExprResult Init);
   ImplicitConversionSequence
   TryObjectArgumentInitialization(QualType FromType, CXXMethodDecl *Method,
                                   CXXRecordDecl *ActingContext);

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=91669&r1=91668&r2=91669&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Thu Dec 17 23:02:21 2009
@@ -3776,6 +3776,9 @@
   // FIXME: Is this enough?
   if (Constructor->isCopyConstructor(Context)) {
     Expr *E = ((Expr **)ExprArgs.get())[0];
+    if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E))
+      if (ICE->getCastKind() == CastExpr::CK_NoOp)
+        E = ICE->getSubExpr();
     while (CXXBindTemporaryExpr *BE = dyn_cast<CXXBindTemporaryExpr>(E))
       E = BE->getSubExpr();
     if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E))

Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=91669&r1=91668&r2=91669&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Thu Dec 17 23:02:21 2009
@@ -450,7 +450,7 @@
     TypeSourceInfo *TInfo
       = Context.getTrivialTypeSourceInfo(AllocType, TypeLoc);
     InitializedEntity Entity
-      = InitializedEntity::InitializeTemporary(TInfo->getTypeLoc());
+      = InitializedEntity::InitializeNew(StartLoc, TInfo->getTypeLoc());
     InitializationSequence InitSeq(*this, Entity, Kind, ConsArgs, NumConsArgs);
     
     if (!InitSeq) {

Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=91669&r1=91668&r2=91669&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Thu Dec 17 23:02:21 2009
@@ -2003,6 +2003,7 @@
 
   case EK_Result:
   case EK_Exception:
+  case EK_New:
   case EK_Temporary:
   case EK_Base:
   case EK_ArrayOrVectorElement:
@@ -2030,6 +2031,7 @@
   case SK_ListInitialization:
   case SK_ConstructorInitialization:
   case SK_ZeroInitialization:
+  case SK_CAssignment:
     break;
     
   case SK_ConversionSequence:
@@ -2115,6 +2117,13 @@
   Steps.push_back(S);
 }
 
+void InitializationSequence::AddCAssignmentStep(QualType T) {
+  Step S;
+  S.Kind = SK_CAssignment;
+  S.Type = T;
+  Steps.push_back(S);
+}
+
 void InitializationSequence::SetOverloadFailure(FailureKind Failure, 
                                                 OverloadingResult Result) {
   SequenceKind = FailedSequence;
@@ -2496,7 +2505,12 @@
     // this into an overloading ambiguity diagnostic. However, we need
     // to keep that set as an OverloadCandidateSet rather than as some
     // other kind of set.
-    Sequence.SetFailed(InitializationSequence::FK_ReferenceInitFailed);
+    if (ConvOvlResult && !Sequence.getFailedCandidateSet().empty())
+      Sequence.SetOverloadFailure(
+                        InitializationSequence::FK_ReferenceInitOverloadFailed,
+                                  ConvOvlResult);
+    else
+      Sequence.SetFailed(InitializationSequence::FK_ReferenceInitFailed);
     return;
   }
 
@@ -2534,7 +2548,10 @@
                                          Expr **Args, unsigned NumArgs,
                                          QualType DestType,
                                          InitializationSequence &Sequence) {
-  Sequence.setSequenceKind(InitializationSequence::ConstructorInitialization);
+  if (Kind.getKind() == InitializationKind::IK_Copy)
+    Sequence.setSequenceKind(InitializationSequence::UserDefinedConversion);
+  else
+    Sequence.setSequenceKind(InitializationSequence::ConstructorInitialization);
   
   // Build the candidate set directly in the initialization sequence
   // structure, so that it will persist if we fail.
@@ -2594,9 +2611,13 @@
   
   // Add the constructor initialization step. Any cv-qualification conversion is
   // subsumed by the initialization.
-  Sequence.AddConstructorInitializationStep(
+  if (Kind.getKind() == InitializationKind::IK_Copy) {
+    Sequence.AddUserConversionStep(Best->Function, DestType);
+  } else {
+    Sequence.AddConstructorInitializationStep(
                                       cast<CXXConstructorDecl>(Best->Function), 
-                                            DestType);
+                                      DestType);
+  }
 }
 
 /// \brief Attempt value initialization (C++ [dcl.init]p7).
@@ -2898,6 +2919,13 @@
     TryDefaultInitialization(S, Entity, Kind, *this);
     return;
   }
+
+  // Handle initialization in C
+  if (!S.getLangOptions().CPlusPlus) {
+    setSequenceKind(CAssignment);
+    AddCAssignmentStep(DestType);
+    return;
+  }
   
   //     - Otherwise, if the destination type is an array, the program is 
   //       ill-formed.
@@ -2965,6 +2993,151 @@
 //===----------------------------------------------------------------------===//
 // Perform initialization
 //===----------------------------------------------------------------------===//
+static Sema::AssignmentAction 
+getAssignmentAction(const InitializedEntity &Entity) {
+  switch(Entity.getKind()) {
+  case InitializedEntity::EK_Variable:
+  case InitializedEntity::EK_New:
+    return Sema::AA_Initializing;
+
+  case InitializedEntity::EK_Parameter:
+    // FIXME: Can we tell when we're sending vs. passing?
+    return Sema::AA_Passing;
+
+  case InitializedEntity::EK_Result:
+    return Sema::AA_Returning;
+
+  case InitializedEntity::EK_Exception:
+  case InitializedEntity::EK_Base:
+    llvm_unreachable("No assignment action for C++-specific initialization");
+    break;
+
+  case InitializedEntity::EK_Temporary:
+    // FIXME: Can we tell apart casting vs. converting?
+    return Sema::AA_Casting;
+    
+  case InitializedEntity::EK_Member:
+  case InitializedEntity::EK_ArrayOrVectorElement:
+    return Sema::AA_Initializing;
+  }
+
+  return Sema::AA_Converting;
+}
+
+static bool shouldBindAsTemporary(const InitializedEntity &Entity,
+                                  bool IsCopy) {
+  switch (Entity.getKind()) {
+  case InitializedEntity::EK_Result:
+  case InitializedEntity::EK_Exception:
+    return !IsCopy;
+      
+  case InitializedEntity::EK_New:
+  case InitializedEntity::EK_Variable:
+  case InitializedEntity::EK_Base:
+  case InitializedEntity::EK_Member:
+  case InitializedEntity::EK_ArrayOrVectorElement:
+    return false;
+    
+  case InitializedEntity::EK_Parameter:
+  case InitializedEntity::EK_Temporary:
+    return true;
+  }
+  
+  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,
+                                             Sema::OwningExprResult CurInit) {
+  SourceLocation Loc;
+  bool isReturn = false;
+  
+  switch (Entity.getKind()) {
+  case InitializedEntity::EK_Result:
+    if (Entity.getType().getType()->isReferenceType())
+      return move(CurInit);
+    isReturn = true;
+    Loc = Entity.getReturnLoc();
+    break;
+      
+  case InitializedEntity::EK_Exception:
+    isReturn = false;
+    Loc = Entity.getThrowLoc();
+    break;
+    
+  case InitializedEntity::EK_Variable:
+  case InitializedEntity::EK_Parameter:
+  case InitializedEntity::EK_New:
+  case InitializedEntity::EK_Temporary:
+  case InitializedEntity::EK_Base:
+  case InitializedEntity::EK_Member:
+  case InitializedEntity::EK_ArrayOrVectorElement:
+    // We don't need to copy for any of these initialized entities.
+    return move(CurInit);
+  }
+  
+  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);
+  
+  // Perform overload resolution using the class's copy constructors.
+  DeclarationName ConstructorName
+    = S.Context.DeclarationNames.getCXXConstructorName(
+                  S.Context.getCanonicalType(S.Context.getTypeDeclType(Class)));
+  DeclContext::lookup_iterator Con, ConEnd;
+  OverloadCandidateSet CandidateSet;
+  for (llvm::tie(Con, ConEnd) = Class->lookup(ConstructorName);
+       Con != ConEnd; ++Con) {
+    // Find the constructor (which may be a template).
+    CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(*Con);
+    if (!Constructor || Constructor->isInvalidDecl() ||
+        !Constructor->isCopyConstructor(S.Context))
+      continue;
+    
+    S.AddOverloadCandidate(Constructor, &CurInitExpr, 1, CandidateSet);
+  }    
+  
+  OverloadCandidateSet::iterator Best;
+  switch (S.BestViableFunction(CandidateSet, Loc, Best)) {
+  case OR_Success:
+    break;
+      
+  case OR_No_Viable_Function:
+    S.Diag(Loc, diag::err_temp_copy_no_viable)
+      << isReturn << CurInitExpr->getType()
+      << CurInitExpr->getSourceRange();
+    S.PrintOverloadCandidates(CandidateSet, false);
+    return S.ExprError();
+      
+  case OR_Ambiguous:
+    S.Diag(Loc, diag::err_temp_copy_ambiguous)
+      << isReturn << CurInitExpr->getType()
+      << CurInitExpr->getSourceRange();
+    S.PrintOverloadCandidates(CandidateSet, true);
+    return S.ExprError();
+    
+  case OR_Deleted:
+    S.Diag(Loc, diag::err_temp_copy_deleted)
+      << isReturn << CurInitExpr->getType()
+      << CurInitExpr->getSourceRange();
+    S.Diag(Best->Function->getLocation(), diag::note_unavailable_here)
+      << Best->Function->isDeleted();
+    return S.ExprError();
+  }
+
+  CurInit.release();
+  return S.BuildCXXConstructExpr(Loc, CurInitExpr->getType(),
+                                 cast<CXXConstructorDecl>(Best->Function),
+                                 /*Elidable=*/true,
+                                 Sema::MultiExprArg(S, 
+                                                    (void**)&CurInitExpr, 1));
+}
 
 Action::OwningExprResult 
 InitializationSequence::Perform(Sema &S,
@@ -3040,26 +3213,26 @@
   // grab the only argument out the Args and place it into the "current"
   // initializer.
   switch (Steps.front().Kind) {
-    case SK_ResolveAddressOfOverloadedFunction:
-    case SK_CastDerivedToBaseRValue:
-    case SK_CastDerivedToBaseLValue:
-    case SK_BindReference:
-    case SK_BindReferenceToTemporary:
-    case SK_UserConversion:
-    case SK_QualificationConversionLValue:
-    case SK_QualificationConversionRValue:
-    case SK_ConversionSequence:
-    case SK_ListInitialization:
-      assert(Args.size() == 1);
-      CurInit = Sema::OwningExprResult(S, 
-                                       ((Expr **)(Args.get()))[0]->Retain());
-      if (CurInit.isInvalid())
-        return S.ExprError();
-      break;
-      
-    case SK_ConstructorInitialization:
-    case SK_ZeroInitialization:
-      break;
+  case SK_ResolveAddressOfOverloadedFunction:
+  case SK_CastDerivedToBaseRValue:
+  case SK_CastDerivedToBaseLValue:
+  case SK_BindReference:
+  case SK_BindReferenceToTemporary:
+  case SK_UserConversion:
+  case SK_QualificationConversionLValue:
+  case SK_QualificationConversionRValue:
+  case SK_ConversionSequence:
+  case SK_ListInitialization:
+  case SK_CAssignment:
+    assert(Args.size() == 1);
+    CurInit = Sema::OwningExprResult(S, ((Expr **)(Args.get()))[0]->Retain());
+    if (CurInit.isInvalid())
+      return S.ExprError();
+    break;
+    
+  case SK_ConstructorInitialization:
+  case SK_ZeroInitialization:
+    break;
   }
     
   // Walk through the computed steps for the initialization sequence, 
@@ -3131,6 +3304,7 @@
       // We have a user-defined conversion that invokes either a constructor
       // or a conversion function.
       CastExpr::CastKind CastKind = CastExpr::CK_Unknown;
+      bool IsCopy = false;
       if (CXXConstructorDecl *Constructor
                               = dyn_cast<CXXConstructorDecl>(Step->Function)) {
         // Build a call to the selected constructor.
@@ -3154,10 +3328,14 @@
           return S.ExprError();
         
         CastKind = CastExpr::CK_ConstructorConversion;
+        QualType Class = S.Context.getTypeDeclType(Constructor->getParent());
+        if (S.Context.hasSameUnqualifiedType(SourceType, Class) ||
+            S.IsDerivedFrom(SourceType, Class))
+          IsCopy = true;
       } else {
         // Build a call to the conversion function.
         CXXConversionDecl *Conversion = cast<CXXConversionDecl>(Step->Function);
-        
+
         // FIXME: Should we move this initialization into a separate 
         // derived-to-base conversion? I believe the answer is "no", because
         // we don't want to turn off access control here for c-style casts.
@@ -3176,12 +3354,17 @@
         CastKind = CastExpr::CK_UserDefinedConversion;
       }
       
-      CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>());
+      if (shouldBindAsTemporary(Entity, IsCopy))
+        CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>());
+
       CurInitExpr = CurInit.takeAs<Expr>();
       CurInit = S.Owned(new (S.Context) ImplicitCastExpr(CurInitExpr->getType(),
                                                          CastKind, 
                                                          CurInitExpr,
-                                                         false));                                                        
+                                                         false));
+      
+      if (!IsCopy)
+        CurInit = CopyIfRequiredForEntity(S, Entity, move(CurInit));
       break;
     }
         
@@ -3235,7 +3418,14 @@
                                         ConstructorInitRequiresZeroInit);
       if (CurInit.isInvalid())
         return S.ExprError();
-          
+      
+      bool Elidable 
+        = cast<CXXConstructExpr>((Expr *)CurInit.get())->isElidable();
+      if (shouldBindAsTemporary(Entity, Elidable))
+        CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>());
+      
+      if (!Elidable)
+        CurInit = CopyIfRequiredForEntity(S, Entity, move(CurInit));
       break;
     }
         
@@ -3258,6 +3448,20 @@
       }
       break;
     }
+
+    case SK_CAssignment: {
+      QualType SourceType = CurInitExpr->getType();
+      Sema::AssignConvertType ConvTy =
+        S.CheckSingleAssignmentConstraints(Step->Type, CurInitExpr);
+      if (S.DiagnoseAssignmentResult(ConvTy, Kind.getLocation(),
+                                     Step->Type, SourceType,
+                                     CurInitExpr, getAssignmentAction(Entity)))
+        return S.ExprError();
+
+      CurInit.release();
+      CurInit = S.Owned(CurInitExpr);
+      break;
+    }
     }
   }
   
@@ -3297,9 +3501,15 @@
   case FK_UserConversionOverloadFailed:
     switch (FailedOverloadResult) {
     case OR_Ambiguous:
-      S.Diag(Kind.getLocation(), diag::err_typecheck_ambiguous_condition)
-        << Args[0]->getType() << DestType.getNonReferenceType()
-        << Args[0]->getSourceRange();
+      if (Failure == FK_UserConversionOverloadFailed)
+        S.Diag(Kind.getLocation(), diag::err_typecheck_ambiguous_condition)
+          << Args[0]->getType() << DestType
+          << Args[0]->getSourceRange();
+      else
+        S.Diag(Kind.getLocation(), diag::err_ref_init_ambiguous)
+          << DestType << Args[0]->getType()
+          << Args[0]->getSourceRange();
+
       S.PrintOverloadCandidates(FailedCandidateSet, true);
       break;
         
@@ -3365,7 +3575,8 @@
     break;
       
   case FK_ConversionFailed:
-    S.Diag(Kind.getLocation(), diag::err_cannot_initialize_decl_noname)
+    S.Diag(Kind.getLocation(), diag::err_init_conversion_failed)
+      << (int)Entity.getKind()
       << DestType
       << (Args[0]->isLvalue(S.Context) == Expr::LV_Valid)
       << Args[0]->getType()
@@ -3448,3 +3659,27 @@
   
   return true;
 }
+
+//===----------------------------------------------------------------------===//
+// Initialization helper functions
+//===----------------------------------------------------------------------===//
+Sema::OwningExprResult 
+Sema::PerformCopyInitialization(const InitializedEntity &Entity,
+                                SourceLocation EqualLoc,
+                                OwningExprResult Init) {
+  if (Init.isInvalid())
+    return ExprError();
+
+  Expr *InitE = (Expr *)Init.get();
+  assert(InitE && "No initialization expression?");
+
+  if (EqualLoc.isInvalid())
+    EqualLoc = InitE->getLocStart();
+
+  InitializationKind Kind = InitializationKind::CreateCopy(InitE->getLocStart(),
+                                                           EqualLoc);
+  InitializationSequence Seq(*this, Entity, Kind, &InitE, 1);
+  Init.release();
+  return Seq.Perform(*this, Entity, Kind, 
+                     MultiExprArg(*this, (void**)&InitE, 1));
+}

Modified: cfe/trunk/lib/Sema/SemaInit.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.h?rev=91669&r1=91668&r2=91669&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.h (original)
+++ cfe/trunk/lib/Sema/SemaInit.h Thu Dec 17 23:02:21 2009
@@ -47,6 +47,9 @@
     /// \brief The entity being initialized is an exception object that
     /// is being thrown.
     EK_Exception,
+    /// \brief The entity being initialized is an object (or array of
+    /// objects) allocated via new.
+    EK_New,
     /// \brief The entity being initialized is a temporary object.
     EK_Temporary,
     /// \brief The entity being initialized is a base member subobject.
@@ -76,9 +79,10 @@
     /// the VarDecl, ParmVarDecl, or FieldDecl, respectively.
     DeclaratorDecl *VariableOrMember;
     
-    /// \brief When Kind == EK_Result or EK_Exception, the location of the 
-    /// 'return' or 'throw' keyword, respectively. When Kind == EK_Temporary,
-    /// the location where the temporary is being created.
+    /// \brief When Kind == EK_Result, EK_Exception, or EK_New, the
+    /// location of the 'return', 'throw', or 'new' keyword,
+    /// respectively. When Kind == EK_Temporary, the location where
+    /// the temporary is being created.
     unsigned Location;
     
     /// \brief When Kind == EK_Base, the base specifier that provides the 
@@ -150,6 +154,11 @@
                                                TypeLoc TL) {
     return InitializedEntity(EK_Exception, ThrowLoc, TL);
   }
+
+  /// \brief Create the initialization entity for an object allocated via new.
+  static InitializedEntity InitializeNew(SourceLocation NewLoc, TypeLoc TL) {
+    return InitializedEntity(EK_New, NewLoc, TL);
+  }
   
   /// \brief Create the initialization entity for a temporary.
   static InitializedEntity InitializeTemporary(TypeLoc TL) {
@@ -373,7 +382,10 @@
     NoInitialization,
     
     /// \brief Standard conversion sequence.
-    StandardConversion
+    StandardConversion,
+
+    /// \brief C conversion sequence.
+    CAssignment
   };
   
   /// \brief Describes the kind of a particular step in an initialization
@@ -404,7 +416,9 @@
     /// \brief Perform initialization via a constructor.
     SK_ConstructorInitialization,
     /// \brief Zero-initialize the object
-    SK_ZeroInitialization
+    SK_ZeroInitialization,
+    /// \brief C assignment
+    SK_CAssignment
   };
   
   /// \brief A single step in the initialization sequence.
@@ -607,6 +621,13 @@
   /// \brief Add a zero-initialization step.
   void AddZeroInitializationStep(QualType T);
   
+  /// \brief Add a C assignment step.
+  //
+  // FIXME: It isn't clear whether this should ever be needed;
+  // ideally, we would handle everything needed in C in the common
+  // path. However, that isn't the case yet.
+  void AddCAssignmentStep(QualType T);
+
   /// \brief Note that this initialization sequence failed.
   void SetFailed(FailureKind Failure) {
     SequenceKind = FailedSequence;

Modified: cfe/trunk/lib/Sema/SemaStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmt.cpp?rev=91669&r1=91668&r2=91669&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaStmt.cpp (original)
+++ cfe/trunk/lib/Sema/SemaStmt.cpp Thu Dec 17 23:02:21 2009
@@ -12,6 +12,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "Sema.h"
+#include "SemaInit.h"
 #include "clang/AST/APValue.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/DeclObjC.h"
@@ -1027,11 +1028,23 @@
     return ActOnBlockReturnStmt(ReturnLoc, RetValExp);
 
   QualType FnRetType;
+  TypeLoc FnRetTypeLoc;
   if (const FunctionDecl *FD = getCurFunctionDecl()) {
     FnRetType = FD->getResultType();
     if (FD->hasAttr<NoReturnAttr>())
       Diag(ReturnLoc, diag::warn_noreturn_function_has_return_expr)
         << getCurFunctionOrMethodDecl()->getDeclName();
+
+#if 0
+    // FIXME: Useful, once we're sure it has all of the information we
+    // need.
+    if (TypeSourceInfo *TInfo = FD->getTypeSourceInfo()) {
+      TypeLoc TL = TInfo->getTypeLoc();
+      if (FunctionTypeLoc *FTL = dyn_cast<FunctionTypeLoc>(&TL))
+        FnRetTypeLoc = FTL->getResultLoc();
+    }
+#endif
+
   } else if (ObjCMethodDecl *MD = getCurMethodDecl())
     FnRetType = MD->getResultType();
   else // If we don't have a function/method context, bail.
@@ -1092,17 +1105,40 @@
     bool Elidable = getLangOptions().CPlusPlus0x ?
                       IsReturnCopyElidable(Context, FnRetType, RetValExp) :
                       false;
+    // FIXME: Elidable
+    (void)Elidable;
+
+    // If we somehow didn't get a 
+
+    // FIXME: Should we allocate the TypeSourceInfo and attach it to
+    // the declaration? Alternatively, we could require that all
+    // function and method declarations have TypeSourceInfos, so that
+    // this is never required.  FIXME: Also, the allocated TInfo goes
+    // into the bump pointer, so it cannot actually be freed.
+    TypeSourceInfo *AllocatedTInfo = 0;
+    if (!FnRetTypeLoc) {
+      const FunctionDecl *FD = getCurFunctionDecl();
+      SourceLocation Loc = FD? FD->getLocation()
+                             : getCurMethodDecl()->getLocation();
+      AllocatedTInfo = Context.getTrivialTypeSourceInfo(FnRetType, Loc);
+      FnRetTypeLoc = AllocatedTInfo->getTypeLoc();
+    }
 
     // In C++ the return statement is handled via a copy initialization.
     // the C version of which boils down to CheckSingleAssignmentConstraints.
-    // FIXME: Leaks RetValExp on error.
-    if (PerformCopyInitialization(RetValExp, FnRetType, AA_Returning, Elidable)){
-      // We should still clean up our temporaries, even when we're failing!
-      RetValExp = MaybeCreateCXXExprWithTemporaries(RetValExp);
+    rex = PerformCopyInitialization(
+                            InitializedEntity::InitializeResult(ReturnLoc, 
+                                                                FnRetTypeLoc),
+                            SourceLocation(),
+                            Owned(RetValExp));
+    if (rex.isInvalid()) {
+      // FIXME: Cleanup temporaries here, anyway?
       return StmtError();
     }
-    
-    if (RetValExp) CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc);
+
+    RetValExp = rex.takeAs<Expr>();
+    if (RetValExp) 
+      CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc);
   }
 
   if (RetValExp)

Modified: cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-var.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-var.cpp?rev=91669&r1=91668&r2=91669&view=diff

==============================================================================
--- cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-var.cpp (original)
+++ cfe/trunk/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-var.cpp Thu Dec 17 23:02:21 2009
@@ -91,7 +91,7 @@
 
 void bind_lvalue_to_conv_lvalue_ambig(ConvertibleToBothDerivedRef both) {
   Derived &dr1 = both;
-  Base &br1 = both; // expected-error{{error: conversion from 'struct ConvertibleToBothDerivedRef' to 'struct Base' is ambiguous}}
+  Base &br1 = both; // expected-error{{reference initialization of type 'struct Base &' with initializer of type 'struct ConvertibleToBothDerivedRef' is ambiguous}}
 }
 
 struct IntBitfield {
@@ -125,5 +125,5 @@
 }
 void bind_lvalue_to_conv_rvalue_ambig(ConvertibleToBothDerived both) {
   const Derived &dr1 = both;
-  const Base &br1 = both; // expected-error{{error: conversion from 'struct ConvertibleToBothDerived' to 'struct Base const' is ambiguous}}
+  const Base &br1 = both; // expected-error{{reference initialization of type 'struct Base const &' with initializer of type 'struct ConvertibleToBothDerived' is ambiguous}}
 }

Modified: cfe/trunk/test/CXX/temp/temp.decls/temp.class/temp.static/p1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.decls/temp.class/temp.static/p1.cpp?rev=91669&r1=91668&r2=91669&view=diff

==============================================================================
--- cfe/trunk/test/CXX/temp/temp.decls/temp.class/temp.static/p1.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.decls/temp.class/temp.static/p1.cpp Thu Dec 17 23:02:21 2009
@@ -17,7 +17,7 @@
 int& get_int() { return X0<int>::value; }
 X1& get_X1() { return X0<X1>::value; }
 
-double*& get_double_ptr() { return X0<int*>::value; } // expected-error{{initialized}}
+double*& get_double_ptr() { return X0<int*>::value; } // expected-error{{non-const lvalue reference to type 'double *' cannot bind to a value of unrelated type 'int *'}}
 
 X2& get_X2() { 
   return X0<X2>::value; // expected-note{{instantiation}}

Modified: cfe/trunk/test/CodeGenCXX/temporaries.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/temporaries.cpp?rev=91669&r1=91668&r2=91669&view=diff

==============================================================================
--- cfe/trunk/test/CodeGenCXX/temporaries.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/temporaries.cpp Thu Dec 17 23:02:21 2009
@@ -202,3 +202,17 @@
   // CHECK: ret void
   f10(h);
 }
+
+// PR5808
+struct I {
+  I(const char *);
+  ~I();
+};
+
+// CHECK: _Z3f12v
+I f12() {
+  // CHECK: call void @_ZN1IC1EPKc
+  // CHECK-NOT: call void @_ZN1ID1Ev
+  // CHECK: ret void
+  return "Hello";
+}

Modified: cfe/trunk/test/SemaCXX/conversion-function.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/conversion-function.cpp?rev=91669&r1=91668&r2=91669&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/conversion-function.cpp (original)
+++ cfe/trunk/test/SemaCXX/conversion-function.cpp Thu Dec 17 23:02:21 2009
@@ -99,7 +99,7 @@
 class AutoPtr {
   // FIXME: Using 'unavailable' since we do not have access control yet.
   // FIXME: The error message isn't so good.
-  AutoPtr(AutoPtr &) __attribute__((unavailable));
+  AutoPtr(AutoPtr &) __attribute__((unavailable)); // expected-note{{explicitly marked}}
   
 public:
   AutoPtr();
@@ -115,9 +115,19 @@
   
   AutoPtr p;
   if (Cond)
-    return p; // expected-error{{incompatible type returning}}
+    return p; // expected-error{{call to deleted constructor}}
   
   return AutoPtr();
 }
 
+struct A1 {
+  A1(const char *);
+  ~A1();
 
+private:
+  A1(const A1&) __attribute__((unavailable)); // expected-note{{here}}
+};
+
+A1 f() {
+  return "Hello"; // expected-error{{invokes deleted copy constructor}}
+}

Modified: cfe/trunk/test/SemaCXX/decl-init-ref.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/decl-init-ref.cpp?rev=91669&r1=91668&r2=91669&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/decl-init-ref.cpp (original)
+++ cfe/trunk/test/SemaCXX/decl-init-ref.cpp Thu Dec 17 23:02:21 2009
@@ -21,6 +21,6 @@
 const int& ri = (void)0; // expected-error {{reference to type 'int const' could not bind to an rvalue of type 'void'}}
 
 int main() {
-        const A& rca = f(); // expected-error {{conversion from 'class B' to 'struct A const' is ambiguous}}
+        const A& rca = f(); // expected-error {{reference initialization of type 'struct A const &' with initializer of type 'class B' is ambiguous}}
         A& ra = f(); // expected-error {{non-const lvalue reference to type 'struct A' cannot bind to a temporary of type 'class B'}}
 }

Modified: cfe/trunk/test/SemaCXX/ref-init-ambiguous.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/ref-init-ambiguous.cpp?rev=91669&r1=91668&r2=91669&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/ref-init-ambiguous.cpp (original)
+++ cfe/trunk/test/SemaCXX/ref-init-ambiguous.cpp Thu Dec 17 23:02:21 2009
@@ -3,19 +3,18 @@
 enum E2 { };
 
 struct A { 
-  operator E2&(); // expected-note 2 {{candidate function}}
+  operator E2&(); // expected-note 3 {{candidate function}}
 };
 
 struct B { 
-  operator E2&(); // expected-note 2 {{candidate function}}
+  operator E2&(); // expected-note 3 {{candidate function}}
 };
 
 struct C : B, A { 
 };
 
 void test(C c) {
-  // FIXME: state that there was an ambiguity in the conversion!
-  const E2 &e2 = c; // expected-error {{reference to type 'enum E2 const' could not bind to an lvalue of type 'struct C'}}
+  const E2 &e2 = c; // expected-error {{reference initialization of type 'enum E2 const &' with initializer of type 'struct C' is ambiguous}}
 }
 
 void foo(const E2 &);

Added: cfe/trunk/test/SemaCXX/rval-references-xfail.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/rval-references-xfail.cpp?rev=91669&view=auto

==============================================================================
--- cfe/trunk/test/SemaCXX/rval-references-xfail.cpp (added)
+++ cfe/trunk/test/SemaCXX/rval-references-xfail.cpp Thu Dec 17 23:02:21 2009
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+// XFAIL: *
+struct MoveOnly {
+  MoveOnly();
+  MoveOnly(const MoveOnly&) = delete;	// expected-note {{candidate function}} \
+  // expected-note 3{{explicitly marked deleted here}}
+  MoveOnly(MoveOnly&&);	// expected-note {{candidate function}}
+  MoveOnly(int&&);	// expected-note {{candidate function}}
+};
+
+MoveOnly returning() {
+  MoveOnly mo;
+  return mo;
+}

Propchange: cfe/trunk/test/SemaCXX/rval-references-xfail.cpp

------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/SemaCXX/rval-references-xfail.cpp

------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/SemaCXX/rval-references-xfail.cpp

------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: cfe/trunk/test/SemaCXX/rval-references.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/rval-references.cpp?rev=91669&r1=91668&r2=91669&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/rval-references.cpp (original)
+++ cfe/trunk/test/SemaCXX/rval-references.cpp Thu Dec 17 23:02:21 2009
@@ -65,27 +65,23 @@
 // Test the return dance. This also tests IsReturnCopyElidable.
 struct MoveOnly {
   MoveOnly();
-  MoveOnly(const MoveOnly&) = delete;	// expected-note {{candidate function}}
+  MoveOnly(const MoveOnly&) = delete;	// expected-note {{candidate function}} \
+  // expected-note 3{{explicitly marked deleted here}}
   MoveOnly(MoveOnly&&);	// expected-note {{candidate function}}
   MoveOnly(int&&);	// expected-note {{candidate function}}
 };
 
-MoveOnly returning() {
-  MoveOnly mo;
-  return mo;
-}
-
 MoveOnly gmo;
 MoveOnly returningNonEligible() {
   int i;
   static MoveOnly mo;
   MoveOnly &r = mo;
   if (0) // Copy from global can't be elided
-    return gmo; // expected-error {{incompatible type returning}}
+    return gmo; // expected-error {{call to deleted constructor}}
   else if (0) // Copy from local static can't be elided
-    return mo; // expected-error {{incompatible type returning}}
+    return mo; // expected-error {{call to deleted constructor}}
   else if (0) // Copy from reference can't be elided
-    return r; // expected-error {{incompatible type returning}}
+    return r; // expected-error {{call to deleted constructor}}
   else // Construction from different type can't be elided
     return i; // expected-error {{no viable conversion from 'int' to 'struct MoveOnly'}}
 }

Modified: cfe/trunk/test/SemaTemplate/class-template-id.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/class-template-id.cpp?rev=91669&r1=91668&r2=91669&view=diff

==============================================================================
--- cfe/trunk/test/SemaTemplate/class-template-id.cpp (original)
+++ cfe/trunk/test/SemaTemplate/class-template-id.cpp Thu Dec 17 23:02:21 2009
@@ -9,9 +9,9 @@
   if (ptr)
     return ptr; // okay
   else if (ptr2)
-    return ptr2; // expected-error{{incompatible type returning 'A<int> const *', expected 'A<int, FLOAT> *'}}
+    return ptr2; // expected-error{{cannot initialize return object of type 'A<int, FLOAT> *' with an lvalue of type 'A<int> const *'}}
   else {
-    return ptr3; // expected-error{{incompatible type returning 'A<int, double> *', expected 'A<int, FLOAT> *'}}
+    return ptr3; // expected-error{{cannot initialize return object of type 'A<int, FLOAT> *' with an lvalue of type 'A<int, double> *'}}
   }
 }
 
@@ -24,7 +24,7 @@
   else if (ptr2)
     return ptr2;
   else
-    return ptr3; // expected-error{{incompatible type returning 'B<19 - 3> *', expected 'B<17 + 2> *'}}
+    return ptr3; // expected-error{{cannot initialize return object of type 'B<17 + 2> *' with an lvalue of type 'B<19 - 3>}}
 }
 
 typedef B<5> B5;

Modified: cfe/trunk/test/SemaTemplate/constructor-template.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/constructor-template.cpp?rev=91669&r1=91668&r2=91669&view=diff

==============================================================================
--- cfe/trunk/test/SemaTemplate/constructor-template.cpp (original)
+++ cfe/trunk/test/SemaTemplate/constructor-template.cpp Thu Dec 17 23:02:21 2009
@@ -52,7 +52,7 @@
 struct B { A<int> x; B(B& a) : x(a.x) {} };
 
 struct X2 {
-  X2();
+  X2(); // expected-note{{candidate function}}
   X2(X2&);	// expected-note {{candidate function}}
   template<typename T> X2(T);
 };
@@ -61,7 +61,7 @@
   if (Cond)
     return x2; // okay, uses copy constructor
   
-  return X2(); // expected-error{{no viable conversion from 'struct X2' to 'struct X2' is possible}}
+  return X2(); // expected-error{{no matching constructor}}
 }
 
 struct X3 {
@@ -71,7 +71,7 @@
 template<> X3::X3(X3); // expected-error{{must pass its first argument by reference}}
 
 struct X4 {
-  X4();
+  X4(); // expected-note{{candidate function}}
   ~X4();
   X4(X4&);	// expected-note {{candidate function}}
   template<typename T> X4(const T&, int = 17);
@@ -80,7 +80,7 @@
 X4 test_X4(bool Cond, X4 x4) {
   X4 a(x4, 17); // okay, constructor template
   X4 b(x4); // okay, copy constructor
-  return X4(); // expected-error{{no viable conversion}}
+  return X4(); // expected-error{{no matching constructor}}
 }
 
 // Instantiation of a non-dependent use of a constructor

Modified: cfe/trunk/test/SemaTemplate/instantiate-expr-4.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/instantiate-expr-4.cpp?rev=91669&r1=91668&r2=91669&view=diff

==============================================================================
--- cfe/trunk/test/SemaTemplate/instantiate-expr-4.cpp (original)
+++ cfe/trunk/test/SemaTemplate/instantiate-expr-4.cpp Thu Dec 17 23:02:21 2009
@@ -293,7 +293,7 @@
 template<typename T>
 struct QualifiedDeclRef0 {
   T f() {
-    return is_pod<X>::value; // expected-error{{initialized}}
+    return is_pod<X>::value; // expected-error{{non-const lvalue reference to type 'int' cannot bind to a value of unrelated type 'bool const'}}
   }
 };
 

Modified: cfe/trunk/test/SemaTemplate/instantiate-function-1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/instantiate-function-1.cpp?rev=91669&r1=91668&r2=91669&view=diff

==============================================================================
--- cfe/trunk/test/SemaTemplate/instantiate-function-1.cpp (original)
+++ cfe/trunk/test/SemaTemplate/instantiate-function-1.cpp Thu Dec 17 23:02:21 2009
@@ -66,7 +66,7 @@
       return u;
     else { 
       if (t < 0)
-        return v; // expected-error{{incompatible type}}
+        return v; // expected-error{{cannot initialize return object of type}}
     }
 
     if (T x = t) {

Modified: cfe/trunk/test/SemaTemplate/instantiate-member-template.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/instantiate-member-template.cpp?rev=91669&r1=91668&r2=91669&view=diff

==============================================================================
--- cfe/trunk/test/SemaTemplate/instantiate-member-template.cpp (original)
+++ cfe/trunk/test/SemaTemplate/instantiate-member-template.cpp Thu Dec 17 23:02:21 2009
@@ -50,7 +50,7 @@
     
     template<typename V>
     V f1(T t, U u, V) {
-      return t + u; // expected-error{{incompatible type}}
+      return t + u; // expected-error{{cannot initialize return object}}
     }
   };
   
@@ -75,7 +75,7 @@
 template<typename U>
 template<typename V>
 V X1<T>::Inner4<U>::f2(T t, U u, V) {
-  return t + u; // expected-error{{incompatible type}}
+  return t + u; // expected-error{{cannot initialize return object}}
 }
 
 void test_X1(int *ip, int i, double *dp) {

Modified: cfe/trunk/test/SemaTemplate/instantiate-typedef.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/instantiate-typedef.cpp?rev=91669&r1=91668&r2=91669&view=diff

==============================================================================
--- cfe/trunk/test/SemaTemplate/instantiate-typedef.cpp (original)
+++ cfe/trunk/test/SemaTemplate/instantiate-typedef.cpp Thu Dec 17 23:02:21 2009
@@ -8,7 +8,7 @@
 add_pointer<int>::type test1(int * ptr) { return ptr; }
 
 add_pointer<float>::type test2(int * ptr) { 
-  return ptr; // expected-error{{incompatible type returning 'int *', expected 'add_pointer<float>::type' (aka 'float *')}}
+  return ptr; // expected-error{{cannot initialize return object of type 'add_pointer<float>::type' (aka 'float *') with an lvalue of type 'int *'}}
 }
 
 add_pointer<int&>::type // expected-note{{in instantiation of template class 'struct add_pointer<int &>' requested here}} \





More information about the cfe-commits mailing list