[cfe-commits] r93162 - in /cfe/trunk: include/clang/AST/DeclarationName.h lib/AST/DeclarationName.cpp lib/AST/TypePrinter.cpp lib/Sema/Sema.h lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaLookup.cpp lib/Sema/SemaOverload.cpp lib/Sema/SemaTemplate.cpp lib/Sema/SemaTemplateDeduction.cpp lib/Sema/SemaType.cpp

Douglas Gregor dgregor at apple.com
Mon Jan 11 10:40:56 PST 2010


Author: dgregor
Date: Mon Jan 11 12:40:55 2010
New Revision: 93162

URL: http://llvm.org/viewvc/llvm-project?rev=93162&view=rev
Log:
Implement name lookup for conversion function template specializations
(C++ [temp.mem]p5-6), which involves template argument deduction based
on the type named, e.g., given

  struct X { template<typename T> operator T*(); } x;

when we call

  x.operator int*();

we perform template argument deduction to determine that T=int. This
template argument deduction is needed for template specialization and
explicit instantiation, e.g.,

  template<> X::operator float*() { /* ... */ }

and when calling or otherwise naming a conversion function (as in the
first example). 

This fixes PR5742 and PR5762, although there's some remaining ugliness
that's causing out-of-line definitions of conversion function
templates to fail. I'll look into that separately.


Modified:
    cfe/trunk/include/clang/AST/DeclarationName.h
    cfe/trunk/lib/AST/DeclarationName.cpp
    cfe/trunk/lib/AST/TypePrinter.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaLookup.cpp
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
    cfe/trunk/lib/Sema/SemaType.cpp

Modified: cfe/trunk/include/clang/AST/DeclarationName.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclarationName.h?rev=93162&r1=93161&r2=93162&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/DeclarationName.h (original)
+++ cfe/trunk/include/clang/AST/DeclarationName.h Mon Jan 11 12:40:55 2010
@@ -190,6 +190,14 @@
   /// getNameKind - Determine what kind of name this is.
   NameKind getNameKind() const;
 
+  /// \brief Determines whether the name itself is dependent, e.g., because it 
+  /// involves a C++ type that is itself dependent.
+  ///
+  /// Note that this does not capture all of the notions of "dependent name",
+  /// because an identifier can be a dependent name if it is used as the 
+  /// callee in a call expression with dependent arguments.
+  bool isDependentName() const;
+  
   /// getName - Retrieve the human-readable string for this name.
   std::string getAsString() const;
 

Modified: cfe/trunk/lib/AST/DeclarationName.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclarationName.cpp?rev=93162&r1=93161&r2=93162&view=diff

==============================================================================
--- cfe/trunk/lib/AST/DeclarationName.cpp (original)
+++ cfe/trunk/lib/AST/DeclarationName.cpp Mon Jan 11 12:40:55 2010
@@ -180,6 +180,11 @@
   return Identifier;
 }
 
+bool DeclarationName::isDependentName() const {
+  QualType T = getCXXNameType();
+  return !T.isNull() && T->isDependentType();
+}
+
 std::string DeclarationName::getAsString() const {
   switch (getNameKind()) {
   case Identifier:

Modified: cfe/trunk/lib/AST/TypePrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/TypePrinter.cpp?rev=93162&r1=93161&r2=93162&view=diff

==============================================================================
--- cfe/trunk/lib/AST/TypePrinter.cpp (original)
+++ cfe/trunk/lib/AST/TypePrinter.cpp Mon Jan 11 12:40:55 2010
@@ -271,6 +271,10 @@
   
   S += ")";
 
+  if (T->getNoReturnAttr())
+    S += " __attribute__((noreturn))";
+
+  
   if (T->hasExceptionSpec()) {
     S += " throw(";
     if (T->hasAnyExceptionSpec())
@@ -287,10 +291,9 @@
     S += ")";
   }
 
-  if (T->getNoReturnAttr())
-    S += " __attribute__((noreturn))";
-  Print(T->getResultType(), S);
+  AppendTypeQualList(S, T->getTypeQuals());
   
+  Print(T->getResultType(), S);
 }
 
 void TypePrinter::PrintFunctionNoProto(const FunctionNoProtoType *T, 

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

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Mon Jan 11 12:40:55 2010
@@ -1178,8 +1178,14 @@
     LookupObjCImplementationName
   };
 
+  /// \brief Specifies whether (or how) name lookup is being performed for a
+  /// redeclaration (vs. a reference).
   enum RedeclarationKind {
-    NotForRedeclaration,
+    /// \brief The lookup is a reference to this name that is not for the
+    /// purpose of redeclaring the name.
+    NotForRedeclaration = 0,
+    /// \brief The lookup results will be used for redeclaration of a name,
+    /// if an entity by that name already exists.
     ForRedeclaration
   };
 

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Mon Jan 11 12:40:55 2010
@@ -2743,7 +2743,9 @@
       << ClassType << ConvType;
   }
 
-  if (Conversion->getPreviousDeclaration()) {
+  if (Conversion->getPrimaryTemplate()) {
+    // ignore specializations
+  } else if (Conversion->getPreviousDeclaration()) {
     const NamedDecl *ExpectedPrevDecl = Conversion->getPreviousDeclaration();
     if (FunctionTemplateDecl *ConversionTemplate
           = Conversion->getDescribedFunctionTemplate())
@@ -2754,7 +2756,7 @@
   } else if (FunctionTemplateDecl *ConversionTemplate
                = Conversion->getDescribedFunctionTemplate())
     ClassDecl->addConversionFunction(ConversionTemplate);
-  else if (!Conversion->getPrimaryTemplate()) // ignore specializations
+  else 
     ClassDecl->addConversionFunction(Conversion);
 
   return DeclPtrTy::make(Conversion);

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Mon Jan 11 12:40:55 2010
@@ -1010,11 +1010,18 @@
 
   // C++ [temp.dep.expr]p3:
   //   An id-expression is type-dependent if it contains:
+  //     -- an identifier that was declared with a dependent type,
+  //        (note: handled after lookup)
+  //     -- a template-id that is dependent,
+  //        (note: handled in BuildTemplateIdExpr)
+  //     -- a conversion-function-id that specifies a dependent type,
   //     -- a nested-name-specifier that contains a class-name that
   //        names a dependent type.
   // Determine whether this is a member of an unknown specialization;
   // we need to handle these differently.
-  if (SS.isSet() && IsDependentIdExpression(*this, SS)) {
+  if ((Name.getNameKind() == DeclarationName::CXXConversionFunctionName &&
+       Name.getCXXNameType()->isDependentType()) ||
+      (SS.isSet() && IsDependentIdExpression(*this, SS))) {
     return ActOnDependentIdExpression(SS, Name, NameLoc,
                                       isAddressOfOperand,
                                       TemplateArgs);
@@ -2281,7 +2288,7 @@
     }
   }
 
-  assert(BaseType->isDependentType());
+  assert(BaseType->isDependentType() || Name.isDependentName());
 
   // Get the type being accessed in BaseType.  If this is an arrow, the BaseExpr
   // must have pointer type, and the accessed type is the pointee.
@@ -3170,7 +3177,7 @@
 
   Expr *Base = BaseArg.takeAs<Expr>();
   OwningExprResult Result(*this);
-  if (Base->getType()->isDependentType()) {
+  if (Base->getType()->isDependentType() || Name.isDependentName()) {
     Result = ActOnDependentMemberExpr(ExprArg(*this, Base), Base->getType(),
                                       IsArrow, OpLoc,
                                       SS, FirstQualifierInScope,

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaLookup.cpp (original)
+++ cfe/trunk/lib/Sema/SemaLookup.cpp Mon Jan 11 12:40:55 2010
@@ -444,10 +444,81 @@
   bool Found = false;
 
   DeclContext::lookup_const_iterator I, E;
-  for (llvm::tie(I, E) = DC->lookup(R.getLookupName()); I != E; ++I)
-    if (R.isAcceptableDecl(*I))
-      R.addDecl(*I), Found = true;
+  for (llvm::tie(I, E) = DC->lookup(R.getLookupName()); I != E; ++I) {
+    if (R.isAcceptableDecl(*I)) {
+      R.addDecl(*I);
+      Found = true;
+    }
+  }
 
+  if (R.getLookupName().getNameKind()
+        == DeclarationName::CXXConversionFunctionName &&
+      !R.getLookupName().getCXXNameType()->isDependentType() &&
+      isa<CXXRecordDecl>(DC)) {
+    // C++ [temp.mem]p6:
+    //   A specialization of a conversion function template is not found by 
+    //   name lookup. Instead, any conversion function templates visible in the
+    //   context of the use are considered. [...]
+    const CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
+    
+    const UnresolvedSet *Unresolved = Record->getConversionFunctions();
+    for (UnresolvedSet::iterator U = Unresolved->begin(), 
+                              UEnd = Unresolved->end();
+         U != UEnd; ++U) {
+      FunctionTemplateDecl *ConvTemplate = dyn_cast<FunctionTemplateDecl>(*U);
+      if (!ConvTemplate)
+        continue;
+      
+      // When we're performing lookup for the purposes of redeclaration, just
+      // add the conversion function template. When we deduce template 
+      // arguments for specializations, we'll end up unifying the return 
+      // type of the new declaration with the type of the function template.
+      if (R.isForRedeclaration()) {
+        R.addDecl(ConvTemplate);
+        Found = true;
+        continue;
+      }
+      
+      // C++ [temp.mem]p6:
+      //   [...] For each such operator, if argument deduction succeeds 
+      //   (14.9.2.3), the resulting specialization is used as if found by 
+      //   name lookup.
+      //
+      // When referencing a conversion function for any purpose other than
+      // a redeclaration (such that we'll be building an expression with the
+      // result), perform template argument deduction and place the 
+      // specialization into the result set. We do this to avoid forcing all
+      // callers to perform special deduction for conversion functions.
+      Sema::TemplateDeductionInfo Info(R.getSema().Context);
+      FunctionDecl *Specialization = 0;
+      
+      const FunctionProtoType *ConvProto        
+        = ConvTemplate->getTemplatedDecl()->getType()
+                                                  ->getAs<FunctionProtoType>();
+      assert(ConvProto && "Nonsensical conversion function template type");
+
+      // Compute the type of the function that we would expect the conversion
+      // function to have, if it were to match the name given.
+      // FIXME: Calling convention!
+      QualType ExpectedType
+        = R.getSema().Context.getFunctionType(
+                                            R.getLookupName().getCXXNameType(),
+                                              0, 0, ConvProto->isVariadic(),
+                                              ConvProto->getTypeQuals(),
+                                              false, false, 0, 0,
+                                              ConvProto->getNoReturnAttr());
+      
+      // Perform template argument deduction against the type that we would
+      // expect the function to have.
+      if (R.getSema().DeduceTemplateArguments(ConvTemplate, 0, ExpectedType,
+                                              Specialization, Info)
+            == Sema::TDK_Success) {
+        R.addDecl(Specialization);
+        Found = true;
+      }
+    }
+  }
+  
   return Found;
 }
 

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Mon Jan 11 12:40:55 2010
@@ -2307,8 +2307,6 @@
   const FunctionProtoType* Proto
     = dyn_cast<FunctionProtoType>(Function->getType()->getAs<FunctionType>());
   assert(Proto && "Functions without a prototype cannot be overloaded");
-  assert(!isa<CXXConversionDecl>(Function) &&
-         "Use AddConversionCandidate for conversion functions");
   assert(!Function->getDescribedFunctionTemplate() &&
          "Use AddTemplateOverloadCandidate for function templates");
 
@@ -2509,8 +2507,6 @@
   const FunctionProtoType* Proto
     = dyn_cast<FunctionProtoType>(Method->getType()->getAs<FunctionType>());
   assert(Proto && "Methods without a prototype cannot be overloaded");
-  assert(!isa<CXXConversionDecl>(Method) &&
-         "Use AddConversionCandidate for conversion functions");
   assert(!isa<CXXConstructorDecl>(Method) &&
          "Use AddOverloadCandidate for constructors");
 

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Mon Jan 11 12:40:55 2010
@@ -4540,8 +4540,10 @@
       if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Prev)) {
         if (Context.hasSameUnqualifiedType(Method->getType(), R)) {
           Matches.clear();
+
           Matches.push_back(Method);
-          break;
+          if (Method->getTemplateSpecializationKind() == TSK_Undeclared)
+            break;
         }
       }
     }
@@ -4553,7 +4555,7 @@
     TemplateDeductionInfo Info(Context);
     FunctionDecl *Specialization = 0;
     if (TemplateDeductionResult TDK
-          = DeduceTemplateArguments(FunTmpl,
+          = DeduceTemplateArguments(FunTmpl, 
                                (HasExplicitTemplateArgs ? &TemplateArgs : 0),
                                     R, Specialization, Info)) {
       // FIXME: Keep track of almost-matches?

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Mon Jan 11 12:40:55 2010
@@ -1312,20 +1312,18 @@
 /// \param FunctionTemplate the function template for which we are performing
 /// template argument deduction.
 ///
-/// \param HasExplicitTemplateArgs whether any template arguments were
-/// explicitly specified.
-///
-/// \param ExplicitTemplateArguments when @p HasExplicitTemplateArgs is true,
-/// the explicitly-specified template arguments.
-///
-/// \param NumExplicitTemplateArguments when @p HasExplicitTemplateArgs is true,
-/// the number of explicitly-specified template arguments in
-/// @p ExplicitTemplateArguments. This value may be zero.
+/// \param ExplicitTemplateArguments the explicit template arguments provided
+/// for this call.
 ///
 /// \param Args the function call arguments
 ///
 /// \param NumArgs the number of arguments in Args
 ///
+/// \param Name the name of the function being called. This is only significant
+/// when the function template is a conversion function template, in which
+/// case this routine will also perform template argument deduction based on
+/// the function to which 
+///
 /// \param Specialization if template argument deduction was successful,
 /// this will be set to the function template specialization produced by
 /// template argument deduction.
@@ -1336,7 +1334,7 @@
 /// \returns the result of template argument deduction.
 Sema::TemplateDeductionResult
 Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
-                              const TemplateArgumentListInfo *ExplicitTemplateArgs,
+                          const TemplateArgumentListInfo *ExplicitTemplateArgs,
                               Expr **Args, unsigned NumArgs,
                               FunctionDecl *&Specialization,
                               TemplateDeductionInfo &Info) {

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Mon Jan 11 12:40:55 2010
@@ -897,12 +897,16 @@
 
   case UnqualifiedId::IK_ConstructorName:
   case UnqualifiedId::IK_DestructorName:
-  case UnqualifiedId::IK_ConversionFunctionId:
     // Constructors and destructors don't have return types. Use
-    // "void" instead. Conversion operators will check their return
-    // types separately.
+    // "void" instead. 
     T = Context.VoidTy;
     break;
+
+  case UnqualifiedId::IK_ConversionFunctionId:
+    // The result type of a conversion function is the type that it
+    // converts to.
+    T = GetTypeFromParser(D.getName().ConversionFunctionId);
+    break;
   }
   
   if (T.isNull())
@@ -1041,7 +1045,8 @@
       const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun;
 
       // C99 6.7.5.3p1: The return type may not be a function or array type.
-      if (T->isArrayType() || T->isFunctionType()) {
+      if ((T->isArrayType() || T->isFunctionType()) &&
+          (D.getName().getKind() != UnqualifiedId::IK_ConversionFunctionId)) {
         Diag(DeclType.Loc, diag::err_func_returning_array_function) << T;
         T = Context.IntTy;
         D.setInvalidType(true);





More information about the cfe-commits mailing list