Fix the problems with template argument deduction and array types for
authorDouglas Gregor <dgregor@apple.com>
Wed, 22 Jul 2009 21:30:48 +0000 (21:30 +0000)
committerDouglas Gregor <dgregor@apple.com>
Wed, 22 Jul 2009 21:30:48 +0000 (21:30 +0000)
real. It turns out that we need to actually move all of the qualifiers
up to the array type itself, then recanonicalize the deduced template
argument type.

llvm-svn: 76788

clang/lib/Sema/SemaTemplateDeduction.cpp
clang/test/SemaTemplate/temp_class_spec.cpp

index deb5457..c71071e 100644 (file)
@@ -283,6 +283,57 @@ DeduceTemplateArguments(ASTContext &Context,
   return Sema::TDK_Success;
 }
 
+/// \brief Returns a completely-unqualified array type, capturing the 
+/// qualifiers in CVRQuals.
+///
+/// \param Context the AST context in which the array type was built.
+///
+/// \param T a canonical type that may be an array type.
+///
+/// \param CVRQuals will receive the set of const/volatile/restrict qualifiers
+/// that were applied to the element type of the array.
+///
+/// \returns if \p T is an array type, the completely unqualified array type
+/// that corresponds to T. Otherwise, returns T.
+static QualType getUnqualifiedArrayType(ASTContext &Context, QualType T,
+                                        unsigned &CVRQuals) {
+  assert(T->isCanonical() && "Only operates on canonical types");
+  if (!isa<ArrayType>(T)) {
+    CVRQuals = T.getCVRQualifiers();
+    return T.getUnqualifiedType();
+  }
+  
+  if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(T)) {
+    QualType Elt = getUnqualifiedArrayType(Context, CAT->getElementType(),
+                                           CVRQuals);
+    if (Elt == CAT->getElementType())
+      return T;
+
+    return Context.getConstantArrayType(Elt, CAT->getSize(), 
+                                        CAT->getSizeModifier(), 0);
+  }
+  
+  if (const IncompleteArrayType *IAT = dyn_cast<IncompleteArrayType>(T)) {
+    QualType Elt = getUnqualifiedArrayType(Context, IAT->getElementType(),
+                                           CVRQuals);
+    if (Elt == IAT->getElementType())
+      return T;
+    
+    return Context.getIncompleteArrayType(Elt, IAT->getSizeModifier(), 0);
+  }
+  
+  const DependentSizedArrayType *DSAT = cast<DependentSizedArrayType>(T);
+  QualType Elt = getUnqualifiedArrayType(Context, DSAT->getElementType(),
+                                         CVRQuals);
+  if (Elt == DSAT->getElementType())
+    return T;
+  
+  // FIXME: Clone expression!
+  return Context.getDependentSizedArrayType(Elt, DSAT->getSizeExpr(),
+                                            DSAT->getSizeModifier(), 0,
+                                            SourceRange());
+}
+
 /// \brief Deduce the template arguments by comparing the parameter type and
 /// the argument type (C++ [temp.deduct.type]).
 ///
@@ -340,14 +391,19 @@ DeduceTemplateArguments(ASTContext &Context,
   if (const TemplateTypeParmType *TemplateTypeParm 
         = Param->getAsTemplateTypeParmType()) {
     unsigned Index = TemplateTypeParm->getIndex();
-
+    bool RecanonicalizeArg = false;
+    
     // If the argument type is an array type, move the qualifiers up to the
     // top level, so they can be matched with the qualifiers on the parameter.
     // FIXME: address spaces, ObjC GC qualifiers
-    QualType ArgElementType = Arg;
-    while (const ArrayType *ArgArray = ArgElementType->getAs<ArrayType>())
-      ArgElementType = ArgArray->getElementType();
-    Arg = Arg.getWithAdditionalQualifiers(ArgElementType.getCVRQualifiers());
+    if (isa<ArrayType>(Arg)) {
+      unsigned CVRQuals = 0;
+      Arg = getUnqualifiedArrayType(Context, Arg, CVRQuals);
+      if (CVRQuals) {
+        Arg = Arg.getWithAdditionalQualifiers(CVRQuals);
+        RecanonicalizeArg = true;
+      }
+    }
                                           
     // The argument type can not be less qualified than the parameter
     // type.
@@ -361,9 +417,10 @@ DeduceTemplateArguments(ASTContext &Context,
     assert(TemplateTypeParm->getDepth() == 0 && "Can't deduce with depth > 0");
          
     unsigned Quals = Arg.getCVRQualifiers() & ~Param.getCVRQualifiers();
-    QualType DeducedType 
-      = Context.getCanonicalType(Arg.getQualifiedType(Quals));
-
+    QualType DeducedType = Arg.getQualifiedType(Quals);
+    if (RecanonicalizeArg)
+      DeducedType = Context.getCanonicalType(DeducedType);
+    
     if (Deduced[Index].isNull())
       Deduced[Index] = TemplateArgument(SourceLocation(), DeducedType);
     else {
index b1053fe..9087b01 100644 (file)
@@ -94,7 +94,20 @@ struct remove_reference<T&> {
 
 int remove_ref0[is_same<remove_reference<int>::type, int>::value? 1 : -1];
 int remove_ref1[is_same<remove_reference<int&>::type, int>::value? 1 : -1];
-                
+
+template<typename T>
+struct remove_const {
+  typedef T type;
+};
+
+template<typename T>
+struct remove_const<const T> {
+  typedef T type;
+};
+
+int remove_const0[is_same<remove_const<const int>::type, int>::value? 1 : -1];
+int remove_const1[is_same<remove_const<const int[3]>::type, int[3]>::value? 1 : -1];
+
 template<typename T>
 struct is_incomplete_array {
   static const bool value = false;