r314231 - Resolve a defect in C++17 copy omission.

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Tue Sep 26 11:37:55 PDT 2017


Author: rsmith
Date: Tue Sep 26 11:37:55 2017
New Revision: 314231

URL: http://llvm.org/viewvc/llvm-project?rev=314231&view=rev
Log:
Resolve a defect in C++17 copy omission.

When selecting constructors for initializing an object of type T from a single
expression of class type U, also consider conversion functions of U that
convert to T (rather than modeling such conversions as calling a conversion
function and then calling a constructor).

This approach is proposed as the resolution for the defect, and is also already
implemented by GCC.

Modified:
    cfe/trunk/include/clang/Sema/Overload.h
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaCodeComplete.cpp
    cfe/trunk/lib/Sema/SemaInit.cpp
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/test/SemaCXX/cxx1z-copy-omission.cpp

Modified: cfe/trunk/include/clang/Sema/Overload.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Overload.h?rev=314231&r1=314230&r2=314231&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Overload.h (original)
+++ cfe/trunk/include/clang/Sema/Overload.h Tue Sep 26 11:37:55 2017
@@ -726,11 +726,20 @@ namespace clang {
     enum CandidateSetKind {
       /// Normal lookup.
       CSK_Normal,
-      /// Lookup for candidates for a call using operator syntax. Candidates
-      /// that have no parameters of class type will be skipped unless there
-      /// is a parameter of (reference to) enum type and the corresponding
-      /// argument is of the same enum type.
-      CSK_Operator
+      /// C++ [over.match.oper]:
+      /// Lookup of operator function candidates in a call using operator
+      /// syntax. Candidates that have no parameters of class type will be
+      /// skipped unless there is a parameter of (reference to) enum type and
+      /// the corresponding argument is of the same enum type.
+      CSK_Operator,
+      /// C++ [over.match.copy]:
+      /// Copy-initialization of an object of class type by user-defined
+      /// conversion.
+      CSK_InitByUserDefinedConversion,
+      /// C++ [over.match.ctor], [over.match.list]
+      /// Initialization of an object of class type by constructor,
+      /// using either a parenthesized or braced list of arguments.
+      CSK_InitByConstructor,
     };
 
   private:
@@ -795,7 +804,7 @@ namespace clang {
     }
 
     /// \brief Clear out all of the candidates.
-    void clear();
+    void clear(CandidateSetKind CSK);
 
     typedef SmallVectorImpl<OverloadCandidate>::iterator iterator;
     iterator begin() { return Candidates.begin(); }
@@ -835,8 +844,7 @@ namespace clang {
 
     /// Find the best viable function on this overload set, if it exists.
     OverloadingResult BestViableFunction(Sema &S, SourceLocation Loc,
-                                         OverloadCandidateSet::iterator& Best,
-                                         bool UserDefinedConversion = false);
+                                         OverloadCandidateSet::iterator& Best);
 
     void NoteCandidates(Sema &S,
                         OverloadCandidateDisplayKind OCD,
@@ -848,10 +856,10 @@ namespace clang {
   };
 
   bool isBetterOverloadCandidate(Sema &S,
-                                 const OverloadCandidate& Cand1,
-                                 const OverloadCandidate& Cand2,
+                                 const OverloadCandidate &Cand1,
+                                 const OverloadCandidate &Cand2,
                                  SourceLocation Loc,
-                                 bool UserDefinedConversion = false);
+                                 OverloadCandidateSet::CandidateSetKind Kind);
 
   struct ConstructorInfo {
     DeclAccessPair FoundDecl;

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=314231&r1=314230&r2=314231&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Tue Sep 26 11:37:55 2017
@@ -2742,13 +2742,15 @@ public:
                               CXXRecordDecl *ActingContext,
                               Expr *From, QualType ToType,
                               OverloadCandidateSet& CandidateSet,
-                              bool AllowObjCConversionOnExplicit);
+                              bool AllowObjCConversionOnExplicit,
+                              bool AllowResultConversion = true);
   void AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate,
                                       DeclAccessPair FoundDecl,
                                       CXXRecordDecl *ActingContext,
                                       Expr *From, QualType ToType,
                                       OverloadCandidateSet &CandidateSet,
-                                      bool AllowObjCConversionOnExplicit);
+                                      bool AllowObjCConversionOnExplicit,
+                                      bool AllowResultConversion = true);
   void AddSurrogateCandidate(CXXConversionDecl *Conversion,
                              DeclAccessPair FoundDecl,
                              CXXRecordDecl *ActingContext,

Modified: cfe/trunk/lib/Sema/SemaCodeComplete.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCodeComplete.cpp?rev=314231&r1=314230&r2=314231&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaCodeComplete.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCodeComplete.cpp Tue Sep 26 11:37:55 2017
@@ -4293,7 +4293,8 @@ static void mergeCandidatesWithResults(S
     std::stable_sort(
         CandidateSet.begin(), CandidateSet.end(),
         [&](const OverloadCandidate &X, const OverloadCandidate &Y) {
-          return isBetterOverloadCandidate(SemaRef, X, Y, Loc);
+          return isBetterOverloadCandidate(SemaRef, X, Y, Loc,
+                                           CandidateSet.getKind());
         });
 
     // Add the remaining viable overload candidates as code-completion results.

Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=314231&r1=314230&r2=314231&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Tue Sep 26 11:37:55 2017
@@ -3531,12 +3531,13 @@ static OverloadingResult
 ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc,
                            MultiExprArg Args,
                            OverloadCandidateSet &CandidateSet,
+                           QualType DestType,
                            DeclContext::lookup_result Ctors,
                            OverloadCandidateSet::iterator &Best,
                            bool CopyInitializing, bool AllowExplicit,
                            bool OnlyListConstructors, bool IsListInit,
                            bool SecondStepOfCopyInit = false) {
-  CandidateSet.clear();
+  CandidateSet.clear(OverloadCandidateSet::CSK_InitByConstructor);
 
   for (NamedDecl *D : Ctors) {
     auto Info = getConstructorInfo(D);
@@ -3587,6 +3588,50 @@ ResolveConstructorOverload(Sema &S, Sour
     }
   }
 
+  // FIXME: Work around a bug in C++17 guaranteed copy elision.
+  //
+  // When initializing an object of class type T by constructor
+  // ([over.match.ctor]) or by list-initialization ([over.match.list])
+  // from a single expression of class type U, conversion functions of
+  // U that convert to the non-reference type cv T are candidates.
+  // Explicit conversion functions are only candidates during
+  // direct-initialization.
+  //
+  // Note: SecondStepOfCopyInit is only ever true in this case when
+  // evaluating whether to produce a C++98 compatibility warning.
+  if (S.getLangOpts().CPlusPlus1z && Args.size() == 1 &&
+      !SecondStepOfCopyInit) {
+    Expr *Initializer = Args[0];
+    auto *SourceRD = Initializer->getType()->getAsCXXRecordDecl();
+    if (SourceRD && S.isCompleteType(DeclLoc, Initializer->getType())) {
+      const auto &Conversions = SourceRD->getVisibleConversionFunctions();
+      for (auto I = Conversions.begin(), E = Conversions.end(); I != E; ++I) {
+        NamedDecl *D = *I;
+        CXXRecordDecl *ActingDC = cast<CXXRecordDecl>(D->getDeclContext());
+        D = D->getUnderlyingDecl();
+
+        FunctionTemplateDecl *ConvTemplate = dyn_cast<FunctionTemplateDecl>(D);
+        CXXConversionDecl *Conv;
+        if (ConvTemplate)
+          Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl());
+        else
+          Conv = cast<CXXConversionDecl>(D);
+
+        if ((AllowExplicit && !CopyInitializing) || !Conv->isExplicit()) {
+          if (ConvTemplate)
+            S.AddTemplateConversionCandidate(ConvTemplate, I.getPair(),
+                                             ActingDC, Initializer, DestType,
+                                             CandidateSet, AllowExplicit,
+                                             /*AllowResultConversion*/false);
+          else
+            S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Initializer,
+                                     DestType, CandidateSet, AllowExplicit,
+                                     /*AllowResultConversion*/false);
+        }
+      }
+    }
+  }
+
   // Perform overload resolution and return the result.
   return CandidateSet.BestViableFunction(S, DeclLoc, Best);
 }
@@ -3686,7 +3731,7 @@ static void TryConstructorInitialization
     // the first phase is omitted.
     if (!(UnwrappedArgs.empty() && DestRecordDecl->hasDefaultConstructor()))
       Result = ResolveConstructorOverload(S, Kind.getLocation(), Args,
-                                          CandidateSet, Ctors, Best,
+                                          CandidateSet, DestType, Ctors, Best,
                                           CopyInitialization, AllowExplicit,
                                           /*OnlyListConstructor=*/true,
                                           IsListInit);
@@ -3700,7 +3745,7 @@ static void TryConstructorInitialization
   if (Result == OR_No_Viable_Function) {
     AsInitializerList = false;
     Result = ResolveConstructorOverload(S, Kind.getLocation(), UnwrappedArgs,
-                                        CandidateSet, Ctors, Best,
+                                        CandidateSet, DestType, Ctors, Best,
                                         CopyInitialization, AllowExplicit,
                                         /*OnlyListConstructors=*/false,
                                         IsListInit);
@@ -3713,6 +3758,24 @@ static void TryConstructorInitialization
     return;
   }
 
+  bool HadMultipleCandidates = (CandidateSet.size() > 1);
+
+  // In C++17, ResolveConstructorOverload can select a conversion function
+  // instead of a constructor.
+  if (auto *CD = dyn_cast<CXXConversionDecl>(Best->Function)) {
+    // Add the user-defined conversion step that calls the conversion function.
+    QualType ConvType = CD->getConversionType();
+    assert(S.Context.hasSameUnqualifiedType(ConvType, DestType) &&
+           "should not have selected this conversion function");
+    Sequence.AddUserConversionStep(CD, Best->FoundDecl, ConvType,
+                                   HadMultipleCandidates);
+    if (!S.Context.hasSameType(ConvType, DestType))
+      Sequence.AddQualificationConversionStep(DestType, VK_RValue);
+    if (IsListInit)
+      Sequence.RewrapReferenceInitList(Entity.getType(), ILE);
+    return;
+  }
+
   // C++11 [dcl.init]p6:
   //   If a program calls for the default initialization of an object
   //   of a const-qualified type T, T shall be a class type with a
@@ -3741,7 +3804,6 @@ static void TryConstructorInitialization
 
   // Add the constructor initialization step. Any cv-qualification conversion is
   // subsumed by the initialization.
-  bool HadMultipleCandidates = (CandidateSet.size() > 1);
   Sequence.AddConstructorInitializationStep(
       Best->FoundDecl, CtorDecl, DestArrayType, HadMultipleCandidates,
       IsListInit | IsInitListCopy, AsInitializerList);
@@ -4087,7 +4149,7 @@ static OverloadingResult TryRefInitWithC
   // Build the candidate set directly in the initialization sequence
   // structure, so that it will persist if we fail.
   OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet();
-  CandidateSet.clear();
+  CandidateSet.clear(OverloadCandidateSet::CSK_InitByUserDefinedConversion);
 
   // Determine whether we are allowed to call explicit constructors or
   // explicit conversion operators.
@@ -4173,7 +4235,7 @@ static OverloadingResult TryRefInitWithC
   // Perform overload resolution. If it fails, return the failed result.
   OverloadCandidateSet::iterator Best;
   if (OverloadingResult Result
-        = CandidateSet.BestViableFunction(S, DeclLoc, Best, true))
+        = CandidateSet.BestViableFunction(S, DeclLoc, Best))
     return Result;
 
   FunctionDecl *Function = Best->Function;
@@ -4687,7 +4749,7 @@ static void TryUserDefinedConversion(Sem
   // Build the candidate set directly in the initialization sequence
   // structure, so that it will persist if we fail.
   OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet();
-  CandidateSet.clear();
+  CandidateSet.clear(OverloadCandidateSet::CSK_InitByUserDefinedConversion);
 
   // Determine whether we are allowed to call explicit constructors or
   // explicit conversion operators.
@@ -4766,7 +4828,7 @@ static void TryUserDefinedConversion(Sem
   // Perform overload resolution. If it fails, return the failed result.
   OverloadCandidateSet::iterator Best;
   if (OverloadingResult Result
-        = CandidateSet.BestViableFunction(S, DeclLoc, Best, true)) {
+        = CandidateSet.BestViableFunction(S, DeclLoc, Best)) {
     Sequence.SetOverloadFailure(
                         InitializationSequence::FK_UserConversionOverloadFailed,
                                 Result);
@@ -5657,7 +5719,7 @@ static ExprResult CopyObject(Sema &S,
 
   OverloadCandidateSet::iterator Best;
   switch (ResolveConstructorOverload(
-      S, Loc, CurInitExpr, CandidateSet, Ctors, Best,
+      S, Loc, CurInitExpr, CandidateSet, T, Ctors, Best,
       /*CopyInitializing=*/false, /*AllowExplicit=*/true,
       /*OnlyListConstructors=*/false, /*IsListInit=*/false,
       /*SecondStepOfCopyInit=*/true)) {
@@ -5797,7 +5859,7 @@ static void CheckCXX98CompatAccessibleCo
   // Perform overload resolution.
   OverloadCandidateSet::iterator Best;
   OverloadingResult OR = ResolveConstructorOverload(
-      S, Loc, CurInitExpr, CandidateSet, Ctors, Best,
+      S, Loc, CurInitExpr, CandidateSet, CurInitExpr->getType(), Ctors, Best,
       /*CopyInitializing=*/false, /*AllowExplicit=*/true,
       /*OnlyListConstructors=*/false, /*IsListInit=*/false,
       /*SecondStepOfCopyInit=*/true);
@@ -7535,8 +7597,7 @@ bool InitializationSequence::Diagnose(Se
         << Args[0]->getSourceRange();
       OverloadCandidateSet::iterator Best;
       OverloadingResult Ovl
-        = FailedCandidateSet.BestViableFunction(S, Kind.getLocation(), Best,
-                                                true);
+        = FailedCandidateSet.BestViableFunction(S, Kind.getLocation(), Best);
       if (Ovl == OR_Deleted) {
         S.NoteDeletedFunction(Best->Function);
       } else {
@@ -8415,7 +8476,7 @@ QualType Sema::DeduceTemplateSpecializat
   OverloadCandidateSet::iterator Best;
   auto tryToResolveOverload =
       [&](bool OnlyListConstructors) -> OverloadingResult {
-    Candidates.clear();
+    Candidates.clear(OverloadCandidateSet::CSK_Normal);
     for (auto I = Guides.begin(), E = Guides.end(); I != E; ++I) {
       NamedDecl *D = (*I)->getUnderlyingDecl();
       if (D->isInvalidDecl())

Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=314231&r1=314230&r2=314231&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Tue Sep 26 11:37:55 2017
@@ -837,12 +837,13 @@ void OverloadCandidateSet::destroyCandid
   }
 }
 
-void OverloadCandidateSet::clear() {
+void OverloadCandidateSet::clear(CandidateSetKind CSK) {
   destroyCandidates();
   SlabAllocator.Reset();
   NumInlineBytesUsed = 0;
   Candidates.clear();
   Functions.clear();
+  Kind = CSK;
 }
 
 namespace {
@@ -3175,6 +3176,7 @@ IsInitializerListConstructorConversion(S
                                        UserDefinedConversionSequence &User,
                                        OverloadCandidateSet &CandidateSet,
                                        bool AllowExplicit) {
+  CandidateSet.clear(OverloadCandidateSet::CSK_InitByUserDefinedConversion);
   for (auto *D : S.LookupConstructors(To)) {
     auto Info = getConstructorInfo(D);
     if (!Info)
@@ -3203,7 +3205,7 @@ IsInitializerListConstructorConversion(S
   OverloadCandidateSet::iterator Best;
   switch (auto Result =
             CandidateSet.BestViableFunction(S, From->getLocStart(),
-                                            Best, true)) {
+                                            Best)) {
   case OR_Deleted:
   case OR_Success: {
     // Record the standard conversion we used and the conversion function.
@@ -3250,6 +3252,7 @@ IsUserDefinedConversion(Sema &S, Expr *F
                         bool AllowExplicit,
                         bool AllowObjCConversionOnExplicit) {
   assert(AllowExplicit || !AllowObjCConversionOnExplicit);
+  CandidateSet.clear(OverloadCandidateSet::CSK_InitByUserDefinedConversion);
 
   // Whether we will only visit constructors.
   bool ConstructorsOnly = false;
@@ -3285,7 +3288,8 @@ IsUserDefinedConversion(Sema &S, Expr *F
         if (Result != OR_No_Viable_Function)
           return Result;
         // Never mind.
-        CandidateSet.clear();
+        CandidateSet.clear(
+            OverloadCandidateSet::CSK_InitByUserDefinedConversion);
 
         // If we're list-initializing, we pass the individual elements as
         // arguments, not the entire list.
@@ -3375,7 +3379,7 @@ IsUserDefinedConversion(Sema &S, Expr *F
 
   OverloadCandidateSet::iterator Best;
   switch (auto Result = CandidateSet.BestViableFunction(S, From->getLocStart(),
-                                                        Best, true)) {
+                                                        Best)) {
   case OR_Success:
   case OR_Deleted:
     // Record the standard conversion we used and the conversion function.
@@ -4309,7 +4313,8 @@ FindConversionForRefInit(Sema &S, Implic
   CXXRecordDecl *T2RecordDecl
     = dyn_cast<CXXRecordDecl>(T2->getAs<RecordType>()->getDecl());
 
-  OverloadCandidateSet CandidateSet(DeclLoc, OverloadCandidateSet::CSK_Normal);
+  OverloadCandidateSet CandidateSet(
+      DeclLoc, OverloadCandidateSet::CSK_InitByUserDefinedConversion);
   const auto &Conversions = T2RecordDecl->getVisibleConversionFunctions();
   for (auto I = Conversions.begin(), E = Conversions.end(); I != E; ++I) {
     NamedDecl *D = *I;
@@ -4379,7 +4384,7 @@ FindConversionForRefInit(Sema &S, Implic
   bool HadMultipleCandidates = (CandidateSet.size() > 1);
 
   OverloadCandidateSet::iterator Best;
-  switch (CandidateSet.BestViableFunction(S, DeclLoc, Best, true)) {
+  switch (CandidateSet.BestViableFunction(S, DeclLoc, Best)) {
   case OR_Success:
     // C++ [over.ics.ref]p1:
     //
@@ -6788,7 +6793,8 @@ Sema::AddConversionCandidate(CXXConversi
                              CXXRecordDecl *ActingContext,
                              Expr *From, QualType ToType,
                              OverloadCandidateSet& CandidateSet,
-                             bool AllowObjCConversionOnExplicit) {
+                             bool AllowObjCConversionOnExplicit,
+                             bool AllowResultConversion) {
   assert(!Conversion->getDescribedFunctionTemplate() &&
          "Conversion function templates use AddTemplateConversionCandidate");
   QualType ConvType = Conversion->getConversionType().getNonReferenceType();
@@ -6803,6 +6809,12 @@ Sema::AddConversionCandidate(CXXConversi
     ConvType = Conversion->getConversionType().getNonReferenceType();
   }
 
+  // If we don't allow any conversion of the result type, ignore conversion
+  // functions that don't convert to exactly (possibly cv-qualified) T.
+  if (!AllowResultConversion &&
+      !Context.hasSameUnqualifiedType(Conversion->getConversionType(), ToType))
+    return;
+
   // Per C++ [over.match.conv]p1, [over.match.ref]p1, an explicit conversion
   // operator is only a candidate if its return type is the target type or
   // can be converted to the target type with a qualification conversion.
@@ -6956,7 +6968,8 @@ Sema::AddTemplateConversionCandidate(Fun
                                      CXXRecordDecl *ActingDC,
                                      Expr *From, QualType ToType,
                                      OverloadCandidateSet &CandidateSet,
-                                     bool AllowObjCConversionOnExplicit) {
+                                     bool AllowObjCConversionOnExplicit,
+                                     bool AllowResultConversion) {
   assert(isa<CXXConversionDecl>(FunctionTemplate->getTemplatedDecl()) &&
          "Only conversion function templates permitted here");
 
@@ -6985,7 +6998,8 @@ Sema::AddTemplateConversionCandidate(Fun
   // template argument deduction as a candidate.
   assert(Specialization && "Missing function template specialization?");
   AddConversionCandidate(Specialization, FoundDecl, ActingDC, From, ToType,
-                         CandidateSet, AllowObjCConversionOnExplicit);
+                         CandidateSet, AllowObjCConversionOnExplicit,
+                         AllowResultConversion);
 }
 
 /// AddSurrogateCandidate - Adds a "surrogate" candidate function that
@@ -8844,10 +8858,9 @@ static Comparison compareEnableIfAttrs(c
 
 /// isBetterOverloadCandidate - Determines whether the first overload
 /// candidate is a better candidate than the second (C++ 13.3.3p1).
-bool clang::isBetterOverloadCandidate(Sema &S, const OverloadCandidate &Cand1,
-                                      const OverloadCandidate &Cand2,
-                                      SourceLocation Loc,
-                                      bool UserDefinedConversion) {
+bool clang::isBetterOverloadCandidate(
+    Sema &S, const OverloadCandidate &Cand1, const OverloadCandidate &Cand2,
+    SourceLocation Loc, OverloadCandidateSet::CandidateSetKind Kind) {
   // Define viable functions to be better candidates than non-viable
   // functions.
   if (!Cand2.Viable)
@@ -8929,7 +8942,8 @@ bool clang::isBetterOverloadCandidate(Se
   //      the type of the entity being initialized) is a better
   //      conversion sequence than the standard conversion sequence
   //      from the return type of F2 to the destination type.
-  if (UserDefinedConversion && Cand1.Function && Cand2.Function &&
+  if (Kind == OverloadCandidateSet::CSK_InitByUserDefinedConversion &&
+      Cand1.Function && Cand2.Function &&
       isa<CXXConversionDecl>(Cand1.Function) &&
       isa<CXXConversionDecl>(Cand2.Function)) {
     // First check whether we prefer one of the conversion functions over the
@@ -9001,6 +9015,18 @@ bool clang::isBetterOverloadCandidate(Se
     // Inherited from sibling base classes: still ambiguous.
   }
 
+  // FIXME: Work around a defect in the C++17 guaranteed copy elision wording,
+  // as combined with the resolution to CWG issue 243.
+  //
+  // When the context is initialization by constructor ([over.match.ctor] or
+  // either phase of [over.match.list]), a constructor is preferred over
+  // a conversion function.
+  if (Kind == OverloadCandidateSet::CSK_InitByConstructor && NumArgs == 1 &&
+      Cand1.Function && Cand2.Function &&
+      isa<CXXConstructorDecl>(Cand1.Function) !=
+          isa<CXXConstructorDecl>(Cand2.Function))
+    return isa<CXXConstructorDecl>(Cand1.Function);
+
   // Check for enable_if value-based overload resolution.
   if (Cand1.Function && Cand2.Function) {
     Comparison Cmp = compareEnableIfAttrs(S, Cand1.Function, Cand2.Function);
@@ -9100,8 +9126,7 @@ void Sema::diagnoseEquivalentInternalLin
 /// \returns The result of overload resolution.
 OverloadingResult
 OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc,
-                                         iterator &Best,
-                                         bool UserDefinedConversion) {
+                                         iterator &Best) {
   llvm::SmallVector<OverloadCandidate *, 16> Candidates;
   std::transform(begin(), end(), std::back_inserter(Candidates),
                  [](OverloadCandidate &Cand) { return &Cand; });
@@ -9135,8 +9160,8 @@ OverloadCandidateSet::BestViableFunction
   Best = end();
   for (auto *Cand : Candidates)
     if (Cand->Viable)
-      if (Best == end() || isBetterOverloadCandidate(S, *Cand, *Best, Loc,
-                                                     UserDefinedConversion))
+      if (Best == end() ||
+          isBetterOverloadCandidate(S, *Cand, *Best, Loc, Kind))
         Best = Cand;
 
   // If we didn't find any viable functions, abort.
@@ -9148,10 +9173,8 @@ OverloadCandidateSet::BestViableFunction
   // Make sure that this function is better than every other viable
   // function. If not, we have an ambiguity.
   for (auto *Cand : Candidates) {
-    if (Cand->Viable &&
-        Cand != Best &&
-        !isBetterOverloadCandidate(S, *Best, *Cand, Loc,
-                                   UserDefinedConversion)) {
+    if (Cand->Viable && Cand != Best &&
+        !isBetterOverloadCandidate(S, *Best, *Cand, Loc, Kind)) {
       if (S.isEquivalentInternalLinkageDeclaration(Best->Function,
                                                    Cand->Function)) {
         EquivalentCands.push_back(Cand->Function);
@@ -10243,9 +10266,12 @@ struct CompareOverloadCandidatesForDispl
   Sema &S;
   SourceLocation Loc;
   size_t NumArgs;
+  OverloadCandidateSet::CandidateSetKind CSK;
 
-  CompareOverloadCandidatesForDisplay(Sema &S, SourceLocation Loc, size_t nArgs)
-      : S(S), NumArgs(nArgs) {}
+  CompareOverloadCandidatesForDisplay(
+      Sema &S, SourceLocation Loc, size_t NArgs,
+      OverloadCandidateSet::CandidateSetKind CSK)
+      : S(S), NumArgs(NArgs) {}
 
   bool operator()(const OverloadCandidate *L,
                   const OverloadCandidate *R) {
@@ -10259,8 +10285,10 @@ struct CompareOverloadCandidatesForDispl
       // TODO: introduce a tri-valued comparison for overload
       // candidates.  Would be more worthwhile if we had a sort
       // that could exploit it.
-      if (isBetterOverloadCandidate(S, *L, *R, SourceLocation())) return true;
-      if (isBetterOverloadCandidate(S, *R, *L, SourceLocation())) return false;
+      if (isBetterOverloadCandidate(S, *L, *R, SourceLocation(), CSK))
+        return true;
+      if (isBetterOverloadCandidate(S, *R, *L, SourceLocation(), CSK))
+        return false;
     } else if (R->Viable)
       return false;
 
@@ -10468,7 +10496,7 @@ void OverloadCandidateSet::NoteCandidate
   }
 
   std::sort(Cands.begin(), Cands.end(),
-            CompareOverloadCandidatesForDisplay(S, OpLoc, Args.size()));
+            CompareOverloadCandidatesForDisplay(S, OpLoc, Args.size(), Kind));
 
   bool ReportedAmbiguousConversions = false;
 
@@ -12917,7 +12945,7 @@ Sema::BuildCallToObjectOfClassType(Scope
   // Perform overload resolution.
   OverloadCandidateSet::iterator Best;
   switch (CandidateSet.BestViableFunction(*this, Object.get()->getLocStart(),
-                             Best)) {
+                                          Best)) {
   case OR_Success:
     // Overload resolution succeeded; we'll build the appropriate call
     // below.
@@ -13311,7 +13339,7 @@ Sema::BuildForRangeBeginEndCall(SourceLo
                                 Expr *Range, ExprResult *CallExpr) {
   Scope *S = nullptr;
 
-  CandidateSet->clear();
+  CandidateSet->clear(OverloadCandidateSet::CSK_Normal);
   if (!MemberLookup.empty()) {
     ExprResult MemberRef =
         BuildMemberReferenceExpr(Range, Range->getType(), Loc,

Modified: cfe/trunk/test/SemaCXX/cxx1z-copy-omission.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx1z-copy-omission.cpp?rev=314231&r1=314230&r2=314231&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx1z-copy-omission.cpp (original)
+++ cfe/trunk/test/SemaCXX/cxx1z-copy-omission.cpp Tue Sep 26 11:37:55 2017
@@ -2,11 +2,11 @@
 
 struct Noncopyable {
   Noncopyable();
-  Noncopyable(const Noncopyable &) = delete; // expected-note 1+{{deleted}}
+  Noncopyable(const Noncopyable &) = delete; // expected-note 1+{{deleted}} expected-note 1+ {{not viable}}
   virtual ~Noncopyable();
 };
 struct Derived : Noncopyable {};
-struct NoncopyableAggr {
+struct NoncopyableAggr { // expected-note 3{{candidate}}
   Noncopyable nc;
 };
 struct Indestructible {
@@ -38,11 +38,39 @@ Noncopyable nrvo() {
 Noncopyable nc1 = make();
 Noncopyable nc2 = Noncopyable();
 Noncopyable nc3 = Derived(); // expected-error {{deleted constructor}}
+Noncopyable nc4((Noncopyable()));
+Noncopyable nc5 = {Noncopyable()};
+Noncopyable nc6{Noncopyable()};
 
 NoncopyableAggr nca1 = NoncopyableAggr{};
 NoncopyableAggr nca2 = NoncopyableAggr{{}};
 NoncopyableAggr nca3 = NoncopyableAggr{NoncopyableAggr{Noncopyable()}};
 
+template<typename T> struct Convert { operator T(); }; // expected-note 1+{{candidate}}
+Noncopyable conv1 = Convert<Noncopyable>();
+Noncopyable conv2((Convert<Noncopyable>()));
+Noncopyable conv3 = {Convert<Noncopyable>()};
+Noncopyable conv4{Convert<Noncopyable>()};
+
+Noncopyable ref_conv1 = Convert<Noncopyable&>(); // expected-error {{deleted constructor}}
+Noncopyable ref_conv2((Convert<Noncopyable&>())); // expected-error {{deleted constructor}}
+Noncopyable ref_conv3 = {Convert<Noncopyable&>()}; // expected-error {{deleted constructor}}
+Noncopyable ref_conv4{Convert<Noncopyable&>()}; // expected-error {{deleted constructor}}
+
+Noncopyable derived_conv1 = Convert<Derived>(); // expected-error {{deleted constructor}}
+Noncopyable derived_conv2((Convert<Derived>())); // expected-error {{deleted constructor}}
+Noncopyable derived_conv3 = {Convert<Derived>()}; // expected-error {{deleted constructor}}
+Noncopyable derived_conv4{Convert<Derived>()}; // expected-error {{deleted constructor}}
+
+NoncopyableAggr nc_aggr1 = Convert<NoncopyableAggr>();
+NoncopyableAggr nc_aggr2((Convert<NoncopyableAggr>()));
+NoncopyableAggr nc_aggr3 = {Convert<NoncopyableAggr>()}; // expected-error {{no viable conversion}}
+NoncopyableAggr nc_aggr4{Convert<NoncopyableAggr>()}; // expected-error {{no viable conversion}}
+NoncopyableAggr nc_aggr5 = Convert<Noncopyable>(); // expected-error {{no viable}}
+NoncopyableAggr nc_aggr6((Convert<Noncopyable>())); // expected-error {{no matching constructor}}
+NoncopyableAggr nc_aggr7 = {Convert<Noncopyable>()};
+NoncopyableAggr nc_aggr8{Convert<Noncopyable>()};
+
 void test_expressions(bool b) {
   auto lambda = [a = make()] {};
 




More information about the cfe-commits mailing list