]> granicus.if.org Git - clang/commitdiff
Implement conversion function templates, along with the ability to use
authorDouglas Gregor <dgregor@apple.com>
Fri, 21 Aug 2009 23:19:43 +0000 (23:19 +0000)
committerDouglas Gregor <dgregor@apple.com>
Fri, 21 Aug 2009 23:19:43 +0000 (23:19 +0000)
template argument deduction from a conversion function (C++
[temp.deduct.conv]) with implicit conversions.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@79693 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/DeclCXX.h
lib/AST/DeclCXX.cpp
lib/Sema/Sema.h
lib/Sema/SemaDeclCXX.cpp
lib/Sema/SemaOverload.cpp
lib/Sema/SemaTemplateDeduction.cpp
lib/Sema/SemaTemplateInstantiateDecl.cpp
test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p2.cpp [new file with mode: 0644]
test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p3.cpp [new file with mode: 0644]
test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p4.cpp [new file with mode: 0644]
www/cxx_status.html

index bffedfcd784f730c916207eb09d89f4ae8d833ed..60db8c83349fbe84b79bdfe1dfef192ec56fbf3b 100644 (file)
@@ -559,6 +559,11 @@ public:
   /// list of conversion functions.
   void addConversionFunction(ASTContext &Context, CXXConversionDecl *ConvDecl);
 
+  /// \brief Add a new conversion function template to the list of conversion
+  /// functions.
+  void addConversionFunction(ASTContext &Context, 
+                             FunctionTemplateDecl *ConvDecl);
+
   /// isAggregate - Whether this class is an aggregate (C++
   /// [dcl.init.aggr]), which is a class with no user-declared
   /// constructors, no private or protected non-static data members,
index 5c0bbec1ff0e6d59dc1d829541b2b26458ba6048..40870bed8dee4bef50209a6b9f54454f974f43cf 100644 (file)
@@ -279,9 +279,17 @@ void CXXRecordDecl::addedAssignmentOperator(ASTContext &Context,
 
 void CXXRecordDecl::addConversionFunction(ASTContext &Context, 
                                           CXXConversionDecl *ConvDecl) {
+  assert(!ConvDecl->getDescribedFunctionTemplate() &&
+         "Conversion function templates should cast to FunctionTemplateDecl.");
   Conversions.addOverload(ConvDecl);
 }
 
+void CXXRecordDecl::addConversionFunction(ASTContext &Context, 
+                                          FunctionTemplateDecl *ConvDecl) {
+  assert(isa<CXXConversionDecl>(ConvDecl->getTemplatedDecl()) &&
+         "Function template is not a conversion function template");
+  Conversions.addOverload(ConvDecl);
+}
 
 CXXConstructorDecl *
 CXXRecordDecl::getDefaultConstructor(ASTContext &Context) {
index 9b9d6ebf0300cbaa56ea8c7e383d3f3ada3f7b90..3e0eae57ce67c36c0610959a6d01c3f1b6976982 100644 (file)
@@ -823,6 +823,9 @@ public:
   void AddConversionCandidate(CXXConversionDecl *Conversion,
                               Expr *From, QualType ToType,
                               OverloadCandidateSet& CandidateSet);
+  void AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate,
+                                      Expr *From, QualType ToType,
+                                      OverloadCandidateSet &CandidateSet);
   void AddSurrogateCandidate(CXXConversionDecl *Conversion,
                              const FunctionProtoType *Proto,
                              Expr *Object, Expr **Args, unsigned NumArgs,
@@ -2552,6 +2555,16 @@ public:
                           FunctionDecl *&Specialization,
                           TemplateDeductionInfo &Info);
   
+  TemplateDeductionResult
+  DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
+                          QualType ToType,
+                          CXXConversionDecl *&Specialization,
+                          TemplateDeductionInfo &Info);
+
+  FunctionTemplateDecl *getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
+                                                   FunctionTemplateDecl *FT2,
+                                                   bool isCallContext);
+
   void MarkDeducedTemplateParameters(const TemplateArgumentList &TemplateArgs,
                                      llvm::SmallVectorImpl<bool> &Deduced);
           
index 49ad45ad7aea626d8e225b2a84a8d9a4bba3a527..79dc24e59662c7044f2ebb72e95889410719299e 100644 (file)
@@ -1853,9 +1853,6 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R,
 Sema::DeclPtrTy Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) {
   assert(Conversion && "Expected to receive a conversion function declaration");
 
-  // Set the lexical context of this conversion function
-  Conversion->setLexicalDeclContext(CurContext);
-
   CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(Conversion->getDeclContext());
 
   // Make sure we aren't redeclaring the conversion function.
@@ -1887,19 +1884,25 @@ Sema::DeclPtrTy Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) {
   }
 
   if (Conversion->getPreviousDeclaration()) {
+    const NamedDecl *ExpectedPrevDecl = Conversion->getPreviousDeclaration();
+    if (FunctionTemplateDecl *ConversionTemplate 
+          = Conversion->getDescribedFunctionTemplate())
+      ExpectedPrevDecl = ConversionTemplate->getPreviousDeclaration();
     OverloadedFunctionDecl *Conversions = ClassDecl->getConversionFunctions();
     for (OverloadedFunctionDecl::function_iterator 
            Conv = Conversions->function_begin(),
            ConvEnd = Conversions->function_end();
          Conv != ConvEnd; ++Conv) {
-      if (*Conv 
-            == cast_or_null<NamedDecl>(Conversion->getPreviousDeclaration())) {
+      if (*Conv == ExpectedPrevDecl) {
         *Conv = Conversion;
         return DeclPtrTy::make(Conversion);
       }
     }
     assert(Conversion->isInvalidDecl() && "Conversion should not get here.");
-  } else 
+  } else if (FunctionTemplateDecl *ConversionTemplate 
+               = Conversion->getDescribedFunctionTemplate())
+    ClassDecl->addConversionFunction(Context, ConversionTemplate);
+  else if (!Conversion->getPrimaryTemplate()) // ignore specializations
     ClassDecl->addConversionFunction(Context, Conversion);
 
   return DeclPtrTy::make(Conversion);
@@ -2845,13 +2848,24 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
     for (OverloadedFunctionDecl::function_iterator Func 
            = Conversions->function_begin();
          Func != Conversions->function_end(); ++Func) {
-      CXXConversionDecl *Conv = cast<CXXConversionDecl>(*Func);
+      FunctionTemplateDecl *ConvTemplate 
+        = dyn_cast<FunctionTemplateDecl>(*Func);
+      CXXConversionDecl *Conv;
+      if (ConvTemplate)
+        Conv = cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl());
+      else
+        Conv = cast<CXXConversionDecl>(*Func);
 
       // If the conversion function doesn't return a reference type,
       // it can't be considered for this conversion.
       if (Conv->getConversionType()->isLValueReferenceType() &&
-          (AllowExplicit || !Conv->isExplicit()))
-        AddConversionCandidate(Conv, Init, DeclType, CandidateSet);
+          (AllowExplicit || !Conv->isExplicit())) {
+        if (ConvTemplate)
+          AddTemplateConversionCandidate(ConvTemplate, Init, DeclType, 
+                                         CandidateSet);
+        else
+          AddConversionCandidate(Conv, Init, DeclType, CandidateSet);
+      }
     }
 
     OverloadCandidateSet::iterator Best;
index f21b38a649e7ae924e347e1185f7f2ce49a1ce26..ada1a2b4328e4d61dbc6d9a126ff89e87f959294 100644 (file)
@@ -1302,6 +1302,19 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType)
     FromType.getUnqualifiedType() == ToType.getUnqualifiedType();
 }
 
+/// \brief Given a function template or function, extract the function template
+/// declaration (if any) and the underlying function declaration.
+template<typename T>
+static void GetFunctionAndTemplate(AnyFunctionDecl Orig, T *&Function,
+                                   FunctionTemplateDecl *&FunctionTemplate) {
+  FunctionTemplate = dyn_cast<FunctionTemplateDecl>(Orig);
+  if (FunctionTemplate)
+    Function = cast<T>(FunctionTemplate->getTemplatedDecl());
+  else
+    Function = cast<T>(Orig);
+}
+
+
 /// Determines whether there is a user-defined conversion sequence
 /// (C++ [over.ics.user]) that converts expression From to the type
 /// ToType. If such a conversion exists, User will contain the
@@ -1381,9 +1394,21 @@ bool Sema::IsUserDefinedConversion(Expr *From, QualType ToType,
       for (OverloadedFunctionDecl::function_iterator Func 
              = Conversions->function_begin();
            Func != Conversions->function_end(); ++Func) {
-        CXXConversionDecl *Conv = cast<CXXConversionDecl>(*Func);
-        if (AllowExplicit || !Conv->isExplicit())
-          AddConversionCandidate(Conv, From, ToType, CandidateSet);
+        CXXConversionDecl *Conv;
+        FunctionTemplateDecl *ConvTemplate;
+        GetFunctionAndTemplate(*Func, Conv, ConvTemplate);
+        if (ConvTemplate)
+          Conv = dyn_cast<CXXConversionDecl>(ConvTemplate->getTemplatedDecl());
+        else 
+          Conv = dyn_cast<CXXConversionDecl>(*Func);
+
+        if (AllowExplicit || !Conv->isExplicit()) {
+          if (ConvTemplate)
+            AddTemplateConversionCandidate(ConvTemplate, From, ToType, 
+                                           CandidateSet);
+          else
+            AddConversionCandidate(Conv, From, ToType, CandidateSet);
+        }
       }
     }
   }
@@ -2295,9 +2320,9 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
                      CandidateSet, SuppressUserConversions, ForceRValue);
 }
 
-/// \brief Add a C++ function template as a candidate in the candidate set,
-/// using template argument deduction to produce an appropriate function
-/// template specialization.
+/// \brief Add a C++ function template specialization as a candidate
+/// in the candidate set, using template argument deduction to produce
+/// an appropriate function template specialization.
 void 
 Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
                                    bool HasExplicitTemplateArgs,
@@ -2345,6 +2370,9 @@ void
 Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
                              Expr *From, QualType ToType,
                              OverloadCandidateSet& CandidateSet) {
+  assert(!Conversion->getDescribedFunctionTemplate() &&
+         "Conversion function templates use AddTemplateConversionCandidate");
+
   // Add this candidate
   CandidateSet.push_back(OverloadCandidate());
   OverloadCandidate& Candidate = CandidateSet.back();
@@ -2404,6 +2432,35 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
   }
 }
 
+/// \brief Adds a conversion function template specialization
+/// candidate to the overload set, using template argument deduction
+/// to deduce the template arguments of the conversion function
+/// template from the type that we are converting to (C++
+/// [temp.deduct.conv]).
+void 
+Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate,
+                                     Expr *From, QualType ToType,
+                                     OverloadCandidateSet &CandidateSet) {
+  assert(isa<CXXConversionDecl>(FunctionTemplate->getTemplatedDecl()) &&
+         "Only conversion function templates permitted here");
+
+  TemplateDeductionInfo Info(Context);
+  CXXConversionDecl *Specialization = 0;
+  if (TemplateDeductionResult Result
+        = DeduceTemplateArguments(FunctionTemplate, ToType, 
+                                  Specialization, Info)) {
+    // FIXME: Record what happened with template argument deduction, so
+    // that we can give the user a beautiful diagnostic.
+    (void)Result;
+    return;
+  }
+                            
+  // Add the conversion function template specialization produced by
+  // template argument deduction as a candidate.
+  assert(Specialization && "Missing function template specialization?");
+  AddConversionCandidate(Specialization, From, ToType, CandidateSet);
+}
+
 /// AddSurrogateCandidate - Adds a "surrogate" candidate function that
 /// converts the given @c Object to a function pointer via the
 /// conversion function @c Conversion, and then attempts to call it
@@ -2801,7 +2858,15 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty,
       for (OverloadedFunctionDecl::function_iterator Func 
              = Conversions->function_begin();
            Func != Conversions->function_end(); ++Func) {
-        CXXConversionDecl *Conv = cast<CXXConversionDecl>(*Func);
+        CXXConversionDecl *Conv;
+        FunctionTemplateDecl *ConvTemplate;
+        GetFunctionAndTemplate(*Func, Conv, ConvTemplate);
+
+        // Skip conversion function templates; they don't tell us anything 
+        // about which builtin types we can convert to.
+        if (ConvTemplate)
+          continue;
+
         if (AllowExplicitConversions || !Conv->isExplicit())
           AddTypesConvertedFrom(Conv->getConversionType(), false, false);
       }
@@ -3543,8 +3608,11 @@ Sema::isBetterOverloadCandidate(const OverloadCandidate& Cand1,
   //      if not that,
   if (Cand1.Function && Cand1.Function->getPrimaryTemplate() &&
       Cand2.Function && Cand2.Function->getPrimaryTemplate())
-    // FIXME: Implement partial ordering of function templates.
-    Diag(SourceLocation(), diag::unsup_function_template_partial_ordering);
+    if (FunctionTemplateDecl *BetterTemplate
+          = getMoreSpecializedTemplate(Cand1.Function->getPrimaryTemplate(),
+                                       Cand2.Function->getPrimaryTemplate(),
+                                       true))
+      return BetterTemplate == Cand1.Function->getPrimaryTemplate();
 
   //   -- the context is an initialization by user-defined conversion
   //      (see 8.5, 13.3.1.5) and the standard conversion sequence
@@ -3842,21 +3910,61 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
   // C++ [over.over]p4:
   //   If more than one function is selected, [...]
   llvm::SmallVector<FunctionDecl *, 4> RemainingMatches;
+  typedef llvm::SmallPtrSet<FunctionDecl *, 4>::iterator MatchIter;
   if (FoundNonTemplateFunction) {
-    // [...] any function template specializations in the set are eliminated 
-    // if the set also contains a non-template function, [...]
-    for (llvm::SmallPtrSet<FunctionDecl *, 4>::iterator M = Matches.begin(),
-                                                     MEnd = Matches.end();
-         M != MEnd; ++M)
+    //   [...] any function template specializations in the set are
+    //   eliminated if the set also contains a non-template function, [...]
+    for (MatchIter M = Matches.begin(), MEnd = Matches.end(); M != MEnd; ++M)
       if ((*M)->getPrimaryTemplate() == 0)
         RemainingMatches.push_back(*M);
   } else {
-    // [...] and any given function template specialization F1 is eliminated 
-    // if the set contains a second function template specialization whose 
-    // function template is more specialized than the function template of F1 
-    // according to the partial ordering rules of 14.5.5.2.
-    // FIXME: Implement this!
-    RemainingMatches.append(Matches.begin(), Matches.end());
+    //   [...] and any given function template specialization F1 is
+    //   eliminated if the set contains a second function template
+    //   specialization whose function template is more specialized
+    //   than the function template of F1 according to the partial
+    //   ordering rules of 14.5.5.2.
+
+    // The algorithm specified above is quadratic. We instead use a
+    // two-pass algorithm (similar to the one used to identify the
+    // best viable function in an overload set) that identifies the
+    // best function template (if it exists).
+    MatchIter Best = Matches.begin();
+    MatchIter M = Best, MEnd = Matches.end();
+    // Find the most specialized function.
+    for (++M; M != MEnd; ++M)
+      if (getMoreSpecializedTemplate((*M)->getPrimaryTemplate(),
+                                     (*Best)->getPrimaryTemplate(),
+                                     false) 
+            == (*M)->getPrimaryTemplate())
+        Best = M;
+
+    // Determine whether this function template is more specialized
+    // that all of the others.
+    bool Ambiguous = false;
+    for (M = Matches.begin(); M != MEnd; ++M) {
+      if (M != Best &&
+          getMoreSpecializedTemplate((*M)->getPrimaryTemplate(),
+                                     (*Best)->getPrimaryTemplate(),
+                                     false)
+           != (*Best)->getPrimaryTemplate()) {
+        Ambiguous = true;
+        break;
+      }
+    }
+
+    // If one function template was more specialized than all of the
+    // others, return it.
+    if (!Ambiguous)
+      return *Best;
+
+    // We could not find a most-specialized function template, which
+    // is equivalent to having a set of function templates with more
+    // than one such template. So, we place all of the function
+    // templates into the set of remaining matches and produce a
+    // diagnostic below. FIXME: we could perform the quadratic
+    // algorithm here, pruning the result set to limit the number of
+    // candidates output later.
+     RemainingMatches.append(Matches.begin(), Matches.end());
   }
   
   // [...] After such eliminations, if any, there shall remain exactly one 
@@ -4468,7 +4576,14 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
          Func = Conversions->function_begin(),
          FuncEnd = Conversions->function_end();
        Func != FuncEnd; ++Func) {
-    CXXConversionDecl *Conv = cast<CXXConversionDecl>(*Func);
+    CXXConversionDecl *Conv;
+    FunctionTemplateDecl *ConvTemplate;
+    GetFunctionAndTemplate(*Func, Conv, ConvTemplate);
+
+    // Skip over templated conversion functions; they aren't
+    // surrogates.
+    if (ConvTemplate)
+      continue;
 
     // Strip the reference type (if any) and then the pointer type (if
     // any) to get down to what might be a function type.
index b3d370ab12ebb90677baba71c4a085fe4f975269..3a1722671ffe0b0c72d7fade9b3f2030bf851ddc 100644 (file)
@@ -1396,8 +1396,11 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
     
     // FIXME: C++0x [temp.deduct.call] paragraphs 6-9 deal with function
     // pointer parameters. 
+
+    // FIXME: we need to check that the deduced A is the same as A,
+    // modulo the various allowed differences.
   }
-  
+
   return FinishTemplateArgumentDeduction(FunctionTemplate, Deduced, 
                                          Specialization, Info);
 }
@@ -1472,6 +1475,141 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
                                          Specialization, Info);
 }
 
+/// \brief Deduce template arguments for a templated conversion
+/// function (C++ [temp.deduct.conv]) and, if successful, produce a
+/// conversion function template specialization.
+Sema::TemplateDeductionResult
+Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
+                              QualType ToType,
+                              CXXConversionDecl *&Specialization,
+                              TemplateDeductionInfo &Info) {
+  CXXConversionDecl *Conv 
+    = cast<CXXConversionDecl>(FunctionTemplate->getTemplatedDecl());
+  QualType FromType = Conv->getConversionType();
+
+  // Canonicalize the types for deduction.
+  QualType P = Context.getCanonicalType(FromType);
+  QualType A = Context.getCanonicalType(ToType);
+
+  // C++0x [temp.deduct.conv]p3:
+  //   If P is a reference type, the type referred to by P is used for
+  //   type deduction.
+  if (const ReferenceType *PRef = P->getAs<ReferenceType>())
+    P = PRef->getPointeeType();
+
+  // C++0x [temp.deduct.conv]p3:
+  //   If A is a reference type, the type referred to by A is used
+  //   for type deduction.
+  if (const ReferenceType *ARef = A->getAs<ReferenceType>())
+    A = ARef->getPointeeType();
+  // C++ [temp.deduct.conv]p2:
+  //
+  //   If A is not a reference type: 
+  else {
+    assert(!A->isReferenceType() && "Reference types were handled above");
+
+    //   - If P is an array type, the pointer type produced by the
+    //     array-to-pointer standard conversion (4.2) is used in place 
+    //     of P for type deduction; otherwise,
+    if (P->isArrayType())
+      P = Context.getArrayDecayedType(P);
+    //   - If P is a function type, the pointer type produced by the
+    //     function-to-pointer standard conversion (4.3) is used in
+    //     place of P for type deduction; otherwise,
+    else if (P->isFunctionType())
+      P = Context.getPointerType(P);
+    //   - If P is a cv-qualified type, the top level cv-qualifiers of
+    //     P’s type are ignored for type deduction.
+    else
+      P = P.getUnqualifiedType();
+
+    // C++0x [temp.deduct.conv]p3:
+    //   If A is a cv-qualified type, the top level cv-qualifiers of A’s
+    //   type are ignored for type deduction.
+    A = A.getUnqualifiedType();
+  }
+
+  // Template argument deduction for function templates in a SFINAE context.
+  // Trap any errors that might occur.
+  SFINAETrap Trap(*this);  
+
+  // C++ [temp.deduct.conv]p1:
+  //   Template argument deduction is done by comparing the return
+  //   type of the template conversion function (call it P) with the
+  //   type that is required as the result of the conversion (call it
+  //   A) as described in 14.8.2.4.
+  TemplateParameterList *TemplateParams
+    = FunctionTemplate->getTemplateParameters();
+  llvm::SmallVector<TemplateArgument, 4> Deduced;
+  Deduced.resize(TemplateParams->size());  
+
+  // C++0x [temp.deduct.conv]p4:
+  //   In general, the deduction process attempts to find template
+  //   argument values that will make the deduced A identical to
+  //   A. However, there are two cases that allow a difference:
+  unsigned TDF = 0;
+  //     - If the original A is a reference type, A can be more
+  //       cv-qualified than the deduced A (i.e., the type referred to
+  //       by the reference)
+  if (ToType->isReferenceType())
+    TDF |= TDF_ParamWithReferenceType;
+  //     - The deduced A can be another pointer or pointer to member
+  //       type that can be converted to A via a qualification
+  //       conversion.
+  //
+  // (C++0x [temp.deduct.conv]p6 clarifies that this only happens when
+  // both P and A are pointers or member pointers. In this case, we
+  // just ignore cv-qualifiers completely).
+  if ((P->isPointerType() && A->isPointerType()) ||
+      (P->isMemberPointerType() && P->isMemberPointerType()))
+    TDF |= TDF_IgnoreQualifiers;
+  if (TemplateDeductionResult Result
+        = ::DeduceTemplateArguments(Context, TemplateParams,
+                                    P, A, Info, Deduced, TDF))
+    return Result;
+
+  // FIXME: we need to check that the deduced A is the same as A,
+  // modulo the various allowed differences.
+  
+  // Finish template argument deduction.
+  FunctionDecl *Spec = 0;
+  TemplateDeductionResult Result
+    = FinishTemplateArgumentDeduction(FunctionTemplate, Deduced, Spec, Info);
+  Specialization = cast_or_null<CXXConversionDecl>(Spec);
+  return Result;
+}
+
+/// \brief Returns the more specialization function template according
+/// to the rules of function template partial ordering (C++ [temp.func.order]).
+///
+/// \param FT1 the first function template
+///
+/// \param FT2 the second function template
+///
+/// \param isCallContext whether partial ordering is being performed
+/// for a function call (which ignores the return types of the
+/// functions).
+/// 
+/// \returns the more specialization function template. If neither
+/// template is more specialized, returns NULL.
+FunctionTemplateDecl *
+Sema::getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
+                                 FunctionTemplateDecl *FT2,
+                                 bool isCallContext) {
+#if 0
+  // FIXME: Implement this
+  bool Better1 = isAtLeastAsSpecializedAs(*this, FT1, FT2, isCallContext);
+  bool Better2 = isAtLeastAsSpecializedAs(*this, FT2, FT1, isCallContext);
+  if (Better1 == Better2)
+    return 0;
+  if (Better1)
+    return FT1;
+  return FT2;
+#else
+  Diag(SourceLocation(), diag::unsup_function_template_partial_ordering);
+  return 0;
+#endif
+}
 
 static void 
 MarkDeducedTemplateParameters(Sema &SemaRef,
index ff97631e72a6301767ddcc2087382c8cdd68229b..ded49b33ab18c15c43482831cb145f1518c792fc 100644 (file)
@@ -505,6 +505,17 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) {
     Method = CXXDestructorDecl::Create(SemaRef.Context, Record,
                                        Destructor->getLocation(), Name,
                                        T, Destructor->isInline(), false);
+  } else if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(D)) {
+    CanQualType ConvTy 
+      = SemaRef.Context.getCanonicalType(
+                                      T->getAsFunctionType()->getResultType());
+    Name = SemaRef.Context.DeclarationNames.getCXXConversionFunctionName(
+                                                                      ConvTy);
+    Method = CXXConversionDecl::Create(SemaRef.Context, Record,
+                                       Conversion->getLocation(), Name,
+                                       T, Conversion->getDeclaratorInfo(),
+                                       Conversion->isInline(), 
+                                       Conversion->isExplicit());
   } else {
     Method = CXXMethodDecl::Create(SemaRef.Context, Record, D->getLocation(), 
                                    D->getDeclName(), T, D->getDeclaratorInfo(),
@@ -541,11 +552,6 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) {
     if (PrevDecl && PrevDecl->getIdentifierNamespace() == Decl::IDNS_Tag)
       PrevDecl = 0;
   }
-  
-  bool Redeclaration = false;
-  bool OverloadableAttrRequired = false;
-  SemaRef.CheckFunctionDeclaration(Method, PrevDecl, Redeclaration,
-                                   /*FIXME:*/OverloadableAttrRequired);
 
   if (FunctionTemplate)
     // Record this function template specialization.
@@ -553,7 +559,13 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) {
                                               FunctionTemplate,
                                               &TemplateArgs,
                                               InsertPos);
-  else if (!Method->isInvalidDecl() || !PrevDecl)
+  
+  bool Redeclaration = false;
+  bool OverloadableAttrRequired = false;
+  SemaRef.CheckFunctionDeclaration(Method, PrevDecl, Redeclaration,
+                                   /*FIXME:*/OverloadableAttrRequired);
+
+  if (!FunctionTemplate && (!Method->isInvalidDecl() || !PrevDecl))
     Owner->addDecl(Method);
   
   return Method;
@@ -568,37 +580,7 @@ Decl *TemplateDeclInstantiator::VisitCXXDestructorDecl(CXXDestructorDecl *D) {
 }
 
 Decl *TemplateDeclInstantiator::VisitCXXConversionDecl(CXXConversionDecl *D) {
-  // FIXME: Look for existing, explicit specializations.
-  Sema::LocalInstantiationScope Scope(SemaRef);
-
-  llvm::SmallVector<ParmVarDecl *, 4> Params;
-  QualType T = InstantiateFunctionType(D, Params);
-  if (T.isNull())
-    return 0;
-  assert(Params.size() == 0 && "Destructor with parameters?");
-
-  // Build the instantiated conversion declaration.
-  CXXRecordDecl *Record = cast<CXXRecordDecl>(Owner);
-  QualType ClassTy = SemaRef.Context.getTypeDeclType(Record);
-  CanQualType ConvTy 
-    = SemaRef.Context.getCanonicalType(T->getAsFunctionType()->getResultType());
-  CXXConversionDecl *Conversion
-    = CXXConversionDecl::Create(SemaRef.Context, Record,
-                                D->getLocation(),
-         SemaRef.Context.DeclarationNames.getCXXConversionFunctionName(ConvTy),
-                                T, D->getDeclaratorInfo(),
-                                D->isInline(), D->isExplicit());
-  Conversion->setInstantiationOfMemberFunction(D);
-  if (InitMethodInstantiation(Conversion, D))
-    Conversion->setInvalidDecl();
-
-  bool Redeclaration = false;
-  bool OverloadableAttrRequired = false;
-  NamedDecl *PrevDecl = 0;
-  SemaRef.CheckFunctionDeclaration(Conversion, PrevDecl, Redeclaration,
-                                   /*FIXME:*/OverloadableAttrRequired);
-  Owner->addDecl(Conversion);
-  return Conversion;  
+  return VisitCXXMethodDecl(D);
 }
 
 ParmVarDecl *TemplateDeclInstantiator::VisitParmVarDecl(ParmVarDecl *D) {
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p2.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p2.cpp
new file mode 100644 (file)
index 0000000..7d17578
--- /dev/null
@@ -0,0 +1,36 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+// FIXME: [temp.deduct.conv]p2 bullets 1 and 2 can't actually happen without
+// references?
+// struct ConvertibleToArray {
+//   //  template<typename T, unsigned N>
+//   //  operator T(()[]) const;
+
+// private:
+//   typedef int array[17];
+
+//   operator array() const;
+// };
+
+// void test_array(ConvertibleToArray cta) {
+//   int *ip = cta;
+//   ip = cta;
+//   const float *cfp = cta;
+// }
+
+// bullet 2
+// struct ConvertibleToFunction {
+//   template<typename T, typename A1, typename A2>
+//   operator T(A1, A2) const ()  { };
+// };
+
+// bullet 3
+struct ConvertibleToCVQuals {
+  template<typename T>
+  operator T* const() const;
+};
+
+void test_cvqual_conv(ConvertibleToCVQuals ctcv) {
+  int *ip = ctcv;
+  const int *icp = ctcv;
+}
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p3.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p3.cpp
new file mode 100644 (file)
index 0000000..95bd7fe
--- /dev/null
@@ -0,0 +1,30 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+struct AnyPtr {
+  template<typename T>
+  operator T*() const;
+};
+
+// If A is a cv-qualified type, the top level cv-qualifiers of A's type
+// are ignored for type deduction.
+void test_cvquals(AnyPtr ap) {
+  int* const ip = ap;
+  const float * const volatile fp = ap;
+}
+
+// If A is a reference type, the type referred to by A is used for
+// type deduction.
+void test_ref_arg(AnyPtr ap) {
+  const int* const &ip = ap;
+  double * const &dp = ap;
+}
+
+struct AnyRef {
+  template<typename T>
+  operator T&() const;
+};
+
+void test_ref_param(AnyRef ar) {
+  int &ir = ar;
+  const float &fr = ar;
+  int i = ar;
+}
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p4.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p4.cpp
new file mode 100644 (file)
index 0000000..439afa8
--- /dev/null
@@ -0,0 +1,48 @@
+// RUN: clang-cc -fsyntax-only %s
+
+struct AnyT {
+  template<typename T>
+  operator T();
+};
+
+void test_cvqual_ref(AnyT any) {
+  const int &cir = any;  
+}
+
+struct AnyThreeLevelPtr {
+  template<typename T>
+  operator T***() const;
+  // FIXME: Can't handle definitions of member templates yet
+#if 0
+  {
+    T x = 0;
+    x = 0; // will fail if T is deduced to a const type
+           // (EDG and GCC get this wrong)
+    return 0;
+  }
+#endif
+};
+
+void test_deduce_with_qual(AnyThreeLevelPtr a3) {
+  int * const * const * const ip = a3;
+}
+
+struct X { };
+
+struct AnyPtrMem {
+  template<typename Class, typename T>
+  operator T Class::*() const;
+  // FIXME: Can't handle definitions of member templates yet
+#if 0
+  {
+    T x = 0;
+    x = 0; // will fail if T is deduced to a const type.
+           // (EDG and GCC get this wrong)
+    return 0;
+  }
+#endif
+};
+
+void test_deduce_ptrmem_with_qual(AnyPtrMem apm) {
+  const float X::* pm = apm;
+}
index 5985e6c5e74bf9fa8f359ff255ad7b29a998084d..be86c5f3ee13747f2db5eee84a00a86d506c1280 100644 (file)
@@ -2111,10 +2111,10 @@ welcome!</p>
 </tr>
 <tr>
   <td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;14.8.2.3 [temp.deduct.conv]</td>
-  <td class="broken" align="center"></td>
-  <td class="broken" align="center"></td>
-  <td class="broken" align="center"></td>
-  <td class="broken" align="center"></td>
+  <td class="na" align="center"></td>
+  <td class="advanced" align="center"></td>
+  <td class="medium" align="center"></td>
+  <td class="na" align="center"></td>
   <td></td>
 </tr>
 <tr>