]> granicus.if.org Git - clang/commitdiff
During template argument deduction from a function call, allow
authorDouglas Gregor <dgregor@apple.com>
Fri, 26 Jun 2009 23:10:12 +0000 (23:10 +0000)
committerDouglas Gregor <dgregor@apple.com>
Fri, 26 Jun 2009 23:10:12 +0000 (23:10 +0000)
deduction from pointer and pointer-to-member types to work even in the
presence of a qualification conversion (C++ [temp.deduct.type]p3
bullet 2).

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

lib/Sema/SemaTemplateDeduction.cpp
test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3.cpp

index bad9e7cf61cc7c4995bfad046024e2ac8856429f..20219d205e027860e04c4fa934e6867568cbb86d 100644 (file)
 #include "clang/AST/ExprCXX.h"
 #include "clang/Parse/DeclSpec.h"
 #include "llvm/Support/Compiler.h"
+
+namespace clang {
+  /// \brief Various flags that control template argument deduction.
+  ///
+  /// These flags can be bitwise-OR'd together.
+  enum TemplateDeductionFlags {
+    /// \brief No template argument deduction flags, which indicates the
+    /// strictest results for template argument deduction (as used for, e.g.,
+    /// matching class template partial specializations).
+    TDF_None = 0,
+    /// \brief Within template argument deduction from a function call, we are
+    /// matching with a parameter type for which the original parameter was
+    /// a reference.
+    TDF_ParamWithReferenceType = 0x1,
+    /// \brief Within template argument deduction from a function call, we
+    /// are matching in a case where we ignore cv-qualifiers.
+    TDF_IgnoreQualifiers = 0x02,
+    /// \brief Within template argument deduction from a function call,
+    /// we are matching in a case where we can perform template argument
+    /// deduction from a derived class of the argument type.
+    /// FIXME: this is completely unsupported right now.
+    TDF_DerivedClass = 0x04
+  };
+}
+
 using namespace clang;
 
 static Sema::TemplateDeductionResult
@@ -171,8 +196,8 @@ DeduceTemplateArguments(ASTContext &Context,
 ///
 /// \param Deduced the deduced template arguments
 ///
-/// \param ParamTypeWasReference if true, the original parameter type was
-/// a reference type (C++0x [temp.deduct.type]p4 bullet 1).
+/// \param TDF bitwise OR of the TemplateDeductionFlags bits that describe
+/// how template argument deduction is performed. 
 ///
 /// \returns the result of template argument deduction so far. Note that a
 /// "success" result means that template argument deduction has not yet failed,
@@ -183,7 +208,7 @@ DeduceTemplateArguments(ASTContext &Context,
                         QualType ParamIn, QualType ArgIn,
                         Sema::TemplateDeductionInfo &Info,
                         llvm::SmallVectorImpl<TemplateArgument> &Deduced,
-                        bool ParamTypeWasReference = false) {
+                        unsigned TDF) {
   // We only want to look at the canonical types, since typedefs and
   // sugar are not part of template argument deduction.
   QualType Param = Context.getCanonicalType(ParamIn);
@@ -193,7 +218,7 @@ DeduceTemplateArguments(ASTContext &Context,
   //   - If the original P is a reference type, the deduced A (i.e., the type
   //     referred to by the reference) can be more cv-qualified than the 
   //     transformed A.
-  if (ParamTypeWasReference) {
+  if (TDF & TDF_ParamWithReferenceType) {
     unsigned ExtraQualsOnParam 
       = Param.getCVRQualifiers() & ~Arg.getCVRQualifiers();
     Param.setCVRQualifiers(Param.getCVRQualifiers() & ~ExtraQualsOnParam);
@@ -216,7 +241,7 @@ DeduceTemplateArguments(ASTContext &Context,
 
     // The argument type can not be less qualified than the parameter
     // type.
-    if (Param.isMoreQualifiedThan(Arg)) {
+    if (Param.isMoreQualifiedThan(Arg) && !(TDF & TDF_IgnoreQualifiers)) {
       Info.Param = cast<TemplateTypeParmDecl>(TemplateParams->getParam(Index));
       Info.FirstArg = Deduced[Index];
       Info.SecondArg = TemplateArgument(SourceLocation(), Arg);
@@ -252,10 +277,16 @@ DeduceTemplateArguments(ASTContext &Context,
   Info.FirstArg = TemplateArgument(SourceLocation(), ParamIn);
   Info.SecondArg = TemplateArgument(SourceLocation(), ArgIn);
 
-  if ((ParamTypeWasReference && Param.isMoreQualifiedThan(Arg)) ||
-      (!ParamTypeWasReference && 
-       (Param.getCVRQualifiers() != Arg.getCVRQualifiers())))
-    return Sema::TDK_NonDeducedMismatch;
+  // Check the cv-qualifiers on the parameter and argument types.
+  if (!(TDF & TDF_IgnoreQualifiers)) {
+    if (TDF & TDF_ParamWithReferenceType) {
+      if (Param.isMoreQualifiedThan(Arg))
+        return Sema::TDK_NonDeducedMismatch;
+    } else {
+      if (Param.getCVRQualifiers() != Arg.getCVRQualifiers())
+        return Sema::TDK_NonDeducedMismatch;  
+    }
+  }
 
   switch (Param->getTypeClass()) {
     // No deduction possible for these types
@@ -271,7 +302,8 @@ DeduceTemplateArguments(ASTContext &Context,
       return DeduceTemplateArguments(Context, TemplateParams,
                                    cast<PointerType>(Param)->getPointeeType(),
                                      PointerArg->getPointeeType(),
-                                     Info, Deduced);
+                                     Info, Deduced, 
+                                     TDF & TDF_IgnoreQualifiers);
     }
       
     //     T &
@@ -283,7 +315,7 @@ DeduceTemplateArguments(ASTContext &Context,
       return DeduceTemplateArguments(Context, TemplateParams,
                            cast<LValueReferenceType>(Param)->getPointeeType(),
                                      ReferenceArg->getPointeeType(),
-                                     Info, Deduced);
+                                     Info, Deduced, 0);
     }
 
     //     T && [C++0x]
@@ -295,7 +327,7 @@ DeduceTemplateArguments(ASTContext &Context,
       return DeduceTemplateArguments(Context, TemplateParams,
                            cast<RValueReferenceType>(Param)->getPointeeType(),
                                      ReferenceArg->getPointeeType(),
-                                     Info, Deduced);
+                                     Info, Deduced, 0);
     }
       
     //     T [] (implied, but not stated explicitly)
@@ -308,7 +340,7 @@ DeduceTemplateArguments(ASTContext &Context,
       return DeduceTemplateArguments(Context, TemplateParams,
                      Context.getAsIncompleteArrayType(Param)->getElementType(),
                                      IncompleteArrayArg->getElementType(),
-                                     Info, Deduced);
+                                     Info, Deduced, 0);
     }
 
     //     T [integer-constant]
@@ -326,7 +358,7 @@ DeduceTemplateArguments(ASTContext &Context,
       return DeduceTemplateArguments(Context, TemplateParams,
                                      ConstantArrayParm->getElementType(),
                                      ConstantArrayArg->getElementType(),
-                                     Info, Deduced);
+                                     Info, Deduced, 0);
     }
 
     //     type [i]
@@ -342,7 +374,7 @@ DeduceTemplateArguments(ASTContext &Context,
             = DeduceTemplateArguments(Context, TemplateParams,
                                       DependentArrayParm->getElementType(),
                                       ArrayArg->getElementType(),
-                                      Info, Deduced))
+                                      Info, Deduced, 0))
         return Result;
           
       // Determine the array bound is something we can deduce.
@@ -398,7 +430,7 @@ DeduceTemplateArguments(ASTContext &Context,
             = DeduceTemplateArguments(Context, TemplateParams,
                                       FunctionProtoParam->getResultType(),
                                       FunctionProtoArg->getResultType(),
-                                      Info, Deduced))
+                                      Info, Deduced, 0))
         return Result;
       
       for (unsigned I = 0, N = FunctionProtoParam->getNumArgs(); I != N; ++I) {
@@ -407,7 +439,7 @@ DeduceTemplateArguments(ASTContext &Context,
               = DeduceTemplateArguments(Context, TemplateParams,
                                         FunctionProtoParam->getArgType(I),
                                         FunctionProtoArg->getArgType(I),
-                                        Info, Deduced))
+                                        Info, Deduced, 0))
           return Result;
       }
       
@@ -516,13 +548,14 @@ DeduceTemplateArguments(ASTContext &Context,
             = DeduceTemplateArguments(Context, TemplateParams,
                                       MemPtrParam->getPointeeType(),
                                       MemPtrArg->getPointeeType(),
-                                      Info, Deduced))
+                                      Info, Deduced,
+                                      TDF & TDF_IgnoreQualifiers))
         return Result;
 
       return DeduceTemplateArguments(Context, TemplateParams,
                                      QualType(MemPtrParam->getClass(), 0),
                                      QualType(MemPtrArg->getClass(), 0),
-                                     Info, Deduced);
+                                     Info, Deduced, 0);
     }
 
     //     (clang extension)
@@ -540,7 +573,7 @@ DeduceTemplateArguments(ASTContext &Context,
       return DeduceTemplateArguments(Context, TemplateParams,
                                      BlockPtrParam->getPointeeType(),
                                      BlockPtrArg->getPointeeType(), Info,
-                                     Deduced);
+                                     Deduced, 0);
     }
 
     case Type::TypeOfExpr:
@@ -571,9 +604,8 @@ DeduceTemplateArguments(ASTContext &Context,
       
   case TemplateArgument::Type: 
     assert(Arg.getKind() == TemplateArgument::Type && "Type/value mismatch");
-    return DeduceTemplateArguments(Context, TemplateParams,
-                                   Param.getAsType(), 
-                                   Arg.getAsType(), Info, Deduced);
+    return DeduceTemplateArguments(Context, TemplateParams, Param.getAsType(),
+                                   Arg.getAsType(), Info, Deduced, 0);
 
   case TemplateArgument::Declaration:
     // FIXME: Implement this check
@@ -921,14 +953,23 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
     //   In general, the deduction process attempts to find template argument
     //   values that will make the deduced A identical to A (after the type A
     //   is transformed as described above). [...]
-    //
-    // FIXME: we'll pass down a flag to indicate when these cases may apply,
-    // and then deal with them in the code that deduces template
-    // arguments from a type.
+    unsigned TDF = 0;
+    
+    //     - If the original P is a reference type, the deduced A (i.e., the
+    //       type referred to by the reference) can be more cv-qualified than
+    //       the transformed A.
+    if (ParamWasReference)
+      TDF |= TDF_ParamWithReferenceType;
+    //     - The transformed A can be another pointer or pointer to member 
+    //       type that can be converted to the deduced A via a qualification 
+    //       conversion (4.4).
+    if (ArgType->isPointerType() || ArgType->isMemberPointerType())
+      TDF |= TDF_IgnoreQualifiers;
+    // FIXME: derived -> base checks
     if (TemplateDeductionResult Result
         = ::DeduceTemplateArguments(Context, TemplateParams,
                                     ParamType, ArgType, Info, Deduced,
-                                    ParamWasReference))
+                                    TDF))
       return Result;
     
     // FIXME: C++ [temp.deduct.call] paragraphs 6-9 deal with function
index 22166d1a7fc2e8149a5a32f165ca60bd98b27108..c014c663598cc4425c2670d8613b40fc396fd1f9 100644 (file)
@@ -48,4 +48,13 @@ void test_f2(int i, const int ci, volatile int vi) {
   A<volatile int> a2 = f2(vi);
 }
 
-// FIXME: the next two bullets require a bit of effort.
\ No newline at end of file
+//   - The transformed A can be another pointer or pointer to member type that 
+//     can be converted to the deduced A via a qualification conversion (4.4).
+template<typename T> A<T> f3(T * * const * const);
+
+void test_f3(int ***ip, volatile int ***vip) {
+  A<int> a0 = f3(ip);
+  A<volatile int> a1 = f3(vip);
+}
+                             
+// FIXME: the next bullet requires a lot of effort.