]> granicus.if.org Git - clang/commitdiff
Eliminate a 'default' case in template argument deduction, where we
authorDouglas Gregor <dgregor@apple.com>
Wed, 15 Jun 2011 16:02:29 +0000 (16:02 +0000)
committerDouglas Gregor <dgregor@apple.com>
Wed, 15 Jun 2011 16:02:29 +0000 (16:02 +0000)
were just punting on template argument deduction for a number of type
nodes. Most of them, obviously, didn't matter.

As a consequence of this, make extended vector types (via the
ext_vector_type attribute) actually work properly for several
important cases:
  - If the attribute appears in a type-id (i.e, not attached to a
  typedef), actually build a proper vector type
  - Build ExtVectorType whenever the size is constant; previously, we
  were building DependentSizedExtVectorType when the size was constant
  but the type was dependent, which makes no sense at all.
  - Teach template argument deduction to handle
  ExtVectorType/DependentSizedExtVectorType.

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

include/clang/Sema/Sema.h
lib/AST/ASTContext.cpp
lib/Sema/SemaDeclAttr.cpp
lib/Sema/SemaTemplateDeduction.cpp
lib/Sema/SemaType.cpp
test/SemaTemplate/ext-vector-type.cpp

index 6dd0d3ceab4c629a4d15c54873c941b33d6061f8..4ddc80a72d5451197d916a91065c58d5cd87c8d1 100644 (file)
@@ -5820,10 +5820,18 @@ private:
   
 protected:
   friend class Parser;
-  friend class InitializationSequence;
+  friend class InitializationSequence;  
   
+public:
   /// \brief Retrieve the parser's current scope.
-  Scope *getCurScope() const { return CurScope; }  
+  ///
+  /// This routine must only be used when it is certain that semantic analysis
+  /// and the parser are in precisely the same context, which is not the case
+  /// when, e.g., we are performing any kind of template instantiation.
+  /// Therefore, the only safe places to use this scope are in the parser
+  /// itself and in routines directly invoked from the parser and *never* from
+  /// template substitution or instantiation.
+  Scope *getCurScope() const { return CurScope; }
 };
 
 /// \brief RAII object that enters a new expression evaluation context.
index 9094abad2ef1c334e68cfbf549ac9d89d44137e5..4c66ed8d7e0f1c1862e654860f9dc25bd1baf0ee 100644 (file)
@@ -1881,7 +1881,7 @@ QualType ASTContext::getVectorType(QualType vecType, unsigned NumElts,
 /// the specified element type and size. VectorType must be a built-in type.
 QualType
 ASTContext::getExtVectorType(QualType vecType, unsigned NumElts) const {
-  assert(vecType->isBuiltinType());
+  assert(vecType->isBuiltinType() || vecType->isDependentType());
 
   // Check if we've already instantiated a vector of this type.
   llvm::FoldingSetNodeID ID;
index 1ec7199562422356e72b74eba2f25dd65bc6be93..430b4f99fb24f25c795eb13fd1184bd39af40ea5 100644 (file)
@@ -217,7 +217,12 @@ static void HandleExtVectorTypeAttr(Scope *scope, Decl *d,
     CXXScopeSpec SS;
     UnqualifiedId id;
     id.setIdentifier(Attr.getParameterName(), Attr.getLoc());
-    sizeExpr = S.ActOnIdExpression(scope, SS, id, false, false).takeAs<Expr>();
+    
+    ExprResult Size = S.ActOnIdExpression(scope, SS, id, false, false);
+    if (Size.isInvalid())
+      return;
+    
+    sizeExpr = Size.get();
   } else {
     // check the attribute arguments.
     if (Attr.getNumArgs() != 1) {
index 842c5fb17d9159f8e9e6e267491360ffceface8c..9011cdf7536ffe50f6c94fbe76add422a0edcb3a 100644 (file)
@@ -1053,10 +1053,39 @@ DeduceTemplateArguments(Sema &S,
   }
 
   switch (Param->getTypeClass()) {
-    // No deduction possible for these types
+    // Non-canonical types cannot appear here.
+#define NON_CANONICAL_TYPE(Class, Base) \
+  case Type::Class: llvm_unreachable("deducing non-canonical type: " #Class);
+#define TYPE(Class, Base)
+#include "clang/AST/TypeNodes.def"
+      
+    case Type::TemplateTypeParm:
+    case Type::SubstTemplateTypeParmPack:
+      llvm_unreachable("Type nodes handled above");
+      
+    // These types cannot be used in templates or cannot be dependent, so
+    // deduction always fails.
     case Type::Builtin:
+    case Type::VariableArray:
+    case Type::Vector:
+    case Type::FunctionNoProto:
+    case Type::Record:
+    case Type::Enum:
+    case Type::ObjCObject:
+    case Type::ObjCInterface:
+    case Type::ObjCObjectPointer:
       return Sema::TDK_NonDeducedMismatch;
 
+    //     _Complex T   [placeholder extension]  
+    case Type::Complex:
+      if (const ComplexType *ComplexArg = Arg->getAs<ComplexType>())
+        return DeduceTemplateArguments(S, TemplateParams, 
+                                    cast<ComplexType>(Param)->getElementType(), 
+                                       ComplexArg->getElementType(),
+                                       Info, Deduced, TDF);
+
+      return Sema::TDK_NonDeducedMismatch;
+      
     //     T *
     case Type::Pointer: {
       QualType PointeeType;
@@ -1360,14 +1389,105 @@ DeduceTemplateArguments(Sema &S,
                                      Deduced, 0);
     }
 
+    //     (clang extension)
+    //
+    //     T __attribute__(((ext_vector_type(<integral constant>))))
+    case Type::ExtVector: {
+      const ExtVectorType *VectorParam = cast<ExtVectorType>(Param);
+      if (const ExtVectorType *VectorArg = dyn_cast<ExtVectorType>(Arg)) {
+        // Make sure that the vectors have the same number of elements.
+        if (VectorParam->getNumElements() != VectorArg->getNumElements())
+          return Sema::TDK_NonDeducedMismatch;
+        
+        // Perform deduction on the element types.
+        return DeduceTemplateArguments(S, TemplateParams,
+                                       VectorParam->getElementType(),
+                                       VectorArg->getElementType(),
+                                       Info, Deduced,
+                                       TDF);
+      }
+      
+      if (const DependentSizedExtVectorType *VectorArg 
+                                = dyn_cast<DependentSizedExtVectorType>(Arg)) {
+        // We can't check the number of elements, since the argument has a
+        // dependent number of elements. This can only occur during partial
+        // ordering.
+
+        // Perform deduction on the element types.
+        return DeduceTemplateArguments(S, TemplateParams,
+                                       VectorParam->getElementType(),
+                                       VectorArg->getElementType(),
+                                       Info, Deduced,
+                                       TDF);
+      }
+      
+      return Sema::TDK_NonDeducedMismatch;
+    }
+      
+    //     (clang extension)
+    //
+    //     T __attribute__(((ext_vector_type(N))))
+    case Type::DependentSizedExtVector: {
+      const DependentSizedExtVectorType *VectorParam
+        = cast<DependentSizedExtVectorType>(Param);
+
+      if (const ExtVectorType *VectorArg = dyn_cast<ExtVectorType>(Arg)) {
+        // Perform deduction on the element types.
+        if (Sema::TemplateDeductionResult Result
+              = DeduceTemplateArguments(S, TemplateParams,
+                                        VectorParam->getElementType(),
+                                        VectorArg->getElementType(),
+                                        Info, Deduced,
+                                        TDF))
+          return Result;
+        
+        // Perform deduction on the vector size, if we can.
+        NonTypeTemplateParmDecl *NTTP
+          = getDeducedParameterFromExpr(VectorParam->getSizeExpr());
+        if (!NTTP)
+          return Sema::TDK_Success;
+
+        llvm::APSInt ArgSize(S.Context.getTypeSize(S.Context.IntTy), false);
+        ArgSize = VectorArg->getNumElements();
+        return DeduceNonTypeTemplateArgument(S, NTTP, ArgSize, S.Context.IntTy,
+                                             false, Info, Deduced);
+      }
+      
+      if (const DependentSizedExtVectorType *VectorArg 
+                                = dyn_cast<DependentSizedExtVectorType>(Arg)) {
+        // Perform deduction on the element types.
+        if (Sema::TemplateDeductionResult Result
+            = DeduceTemplateArguments(S, TemplateParams,
+                                      VectorParam->getElementType(),
+                                      VectorArg->getElementType(),
+                                      Info, Deduced,
+                                      TDF))
+          return Result;
+        
+        // Perform deduction on the vector size, if we can.
+        NonTypeTemplateParmDecl *NTTP
+          = getDeducedParameterFromExpr(VectorParam->getSizeExpr());
+        if (!NTTP)
+          return Sema::TDK_Success;
+        
+        return DeduceNonTypeTemplateArgument(S, NTTP, VectorArg->getSizeExpr(),
+                                             Info, Deduced);
+      }
+      
+      return Sema::TDK_NonDeducedMismatch;
+    }
+      
     case Type::TypeOfExpr:
     case Type::TypeOf:
     case Type::DependentName:
+    case Type::UnresolvedUsing:
+    case Type::Decltype:
+    case Type::UnaryTransform:
+    case Type::Auto:
+    case Type::DependentTemplateSpecialization:
+    case Type::PackExpansion:
       // No template argument deduction for these types
       return Sema::TDK_Success;
-
-    default:
-      break;
   }
 
   // FIXME: Many more cases to go (to go).
index ec8fdc917c05408ff5d04a9deec270377dfb862e..ef3c2624b2c2dde2c9e1a3f00c46a393fe646237 100644 (file)
@@ -1320,8 +1320,7 @@ QualType Sema::BuildExtVectorType(QualType T, Expr *ArraySize,
       return QualType();
     }
 
-    if (!T->isDependentType())
-      return Context.getExtVectorType(T, vectorSize);
+    return Context.getExtVectorType(T, vectorSize);
   }
 
   return Context.getDependentSizedExtVectorType(T, ArraySize, AttrLoc);
@@ -3151,6 +3150,40 @@ static void HandleVectorSizeAttr(QualType& CurType, const AttributeList &Attr,
                                     VectorType::GenericVector);
 }
 
+/// \brief Process the OpenCL-like ext_vector_type attribute when it occurs on
+/// a type.
+static void HandleExtVectorTypeAttr(QualType &CurType, 
+                                    const AttributeList &Attr, 
+                                    Sema &S) {
+  Expr *sizeExpr;
+  
+  // Special case where the argument is a template id.
+  if (Attr.getParameterName()) {
+    CXXScopeSpec SS;
+    UnqualifiedId id;
+    id.setIdentifier(Attr.getParameterName(), Attr.getLoc());
+    
+    ExprResult Size = S.ActOnIdExpression(S.getCurScope(), SS, id, false, 
+                                          false);
+    if (Size.isInvalid())
+      return;
+    
+    sizeExpr = Size.get();
+  } else {
+    // check the attribute arguments.
+    if (Attr.getNumArgs() != 1) {
+      S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+      return;
+    }
+    sizeExpr = Attr.getArg(0);
+  }
+  
+  // Create the vector type.
+  QualType T = S.BuildExtVectorType(CurType, sizeExpr, Attr.getLoc());
+  if (!T.isNull())
+    CurType = T;
+}
+
 /// HandleNeonVectorTypeAttr - The "neon_vector_type" and
 /// "neon_polyvector_type" attributes are used to create vector types that
 /// are mangled according to ARM's ABI.  Otherwise, these types are identical
@@ -3241,6 +3274,11 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
     case AttributeList::AT_vector_size:
       HandleVectorSizeAttr(type, attr, state.getSema());
       break;
+    case AttributeList::AT_ext_vector_type:
+      if (state.getDeclarator().getDeclSpec().getStorageClassSpec()
+            != DeclSpec::SCS_typedef)
+        HandleExtVectorTypeAttr(type, attr, state.getSema());
+      break;
     case AttributeList::AT_neon_vector_type:
       HandleNeonVectorTypeAttr(type, attr, state.getSema(),
                                VectorType::NeonVector, "neon_vector_type");
index 7334e88e9267d50d87b032ece9ad4fe171485baf..f968c13f10238e97c8e349e8e0a35127cd2d273a 100644 (file)
@@ -58,3 +58,37 @@ int test_make6() {
   y.x = -1;
   y.w = -1; // expected-error{{vector component access exceeds type}}
 }
+
+namespace Deduction {
+  template<typename T> struct X0;
+
+  template<typename T, unsigned N>
+  struct X0<T __attribute__((ext_vector_type(N)))> {
+    static const unsigned value = 0;
+  };
+
+  template<typename T>
+  struct X0<T __attribute__((ext_vector_type(4)))> {
+    static const unsigned value = 1;
+  };
+
+  template<unsigned N>
+  struct X0<float __attribute__((ext_vector_type(N)))> {
+    static const unsigned value = 2;
+  };
+
+  template<>
+  struct X0<float __attribute__((ext_vector_type(4)))> {
+    static const unsigned value = 3;
+  };
+
+  typedef int __attribute__((ext_vector_type(2))) int2;
+  typedef int __attribute__((ext_vector_type(4))) int4;
+  typedef float __attribute__((ext_vector_type(2))) float2;
+  typedef float __attribute__((ext_vector_type(4))) float4;
+
+  int array0[X0<int2>::value == 0? 1 : -1];
+  int array1[X0<int4>::value == 1? 1 : -1];
+  int array2[X0<float2>::value == 2? 1 : -1];
+  int array3[X0<float4>::value == 3? 1 : -1];
+}