Support dependent extended vector types and template instantiation
thereof. Patch by Anders Johnsen!


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@73641 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 28fb918..bbfab88 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -359,6 +359,8 @@
   QualType BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
                           Expr *ArraySize, unsigned Quals,
                           SourceLocation Loc, DeclarationName Entity);
+  QualType BuildExtVectorType(QualType T, ExprArg ArraySize, 
+                              SourceLocation AttrLoc);
   QualType BuildFunctionType(QualType T,
                              QualType *ParamTypes, unsigned NumParamTypes,
                              bool Variadic, unsigned Quals,
@@ -1116,8 +1118,8 @@
   // More parsing and symbol table subroutines.
 
   // Decl attributes - this routine is the top level dispatcher. 
-  void ProcessDeclAttributes(Decl *D, const Declarator &PD);
-  void ProcessDeclAttributeList(Decl *D, const AttributeList *AttrList);
+  void ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD);
+  void ProcessDeclAttributeList(Scope *S, Decl *D, const AttributeList *AttrList);
 
   void WarnUndefinedMethod(SourceLocation ImpLoc, ObjCMethodDecl *method,
                            bool &IncompleteImpl);
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index b995717..829ea91 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -1615,7 +1615,7 @@
     NewTD->setInvalidDecl();
 
   // Handle attributes prior to checking for duplicates in MergeVarDecl
-  ProcessDeclAttributes(NewTD, D);
+  ProcessDeclAttributes(S, NewTD, D);
   // Merge the decl with the existing one if appropriate. If the decl is
   // in an outer scope, it isn't the same thing.
   if (PrevDecl && isDeclInScope(PrevDecl, DC, S)) {
@@ -1801,7 +1801,7 @@
   NewVD->setLexicalDeclContext(CurContext);
 
   // Handle attributes prior to checking for duplicates in MergeVarDecl
-  ProcessDeclAttributes(NewVD, D);
+  ProcessDeclAttributes(S, NewVD, D);
 
   // Handle GNU asm-label extension (encoded as an attribute).
   if (Expr *E = (Expr*) D.getAsmLabel()) {
@@ -2298,7 +2298,7 @@
   // (for example to check for conflicts, etc).
   // FIXME: This needs to happen before we merge declarations. Then,
   // let attribute merging cope with attribute conflicts.
-  ProcessDeclAttributes(NewFD, D);
+  ProcessDeclAttributes(S, NewFD, D);
   AddKnownFunctionAttributes(NewFD);
 
   if (OverloadableAttrRequired && !NewFD->getAttr<OverloadableAttr>()) {
@@ -2907,7 +2907,7 @@
   if (II)
     IdResolver.AddDecl(New);
 
-  ProcessDeclAttributes(New, D);
+  ProcessDeclAttributes(S, New, D);
 
   if (New->hasAttr<BlocksAttr>()) {
     Diag(New->getLocation(), diag::err_block_on_nonlocal);
@@ -3628,7 +3628,7 @@
     New->setInvalidDecl();
 
   if (Attr)
-    ProcessDeclAttributeList(New, Attr);
+    ProcessDeclAttributeList(S, New, Attr);
 
   // If we're declaring or defining a tag in function prototype scope
   // in C, note that this type can only be used within the function.
@@ -3878,7 +3878,8 @@
   // FIXME: We need to pass in the attributes given an AST
   // representation, not a parser representation.
   if (D)
-    ProcessDeclAttributes(NewFD, *D);
+    // FIXME: What to pass instead of TUScope?
+    ProcessDeclAttributes(TUScope, NewFD, *D);
 
   if (T.isObjCGCWeak())
     Diag(Loc, diag::warn_attribute_weak_on_field);
@@ -3985,7 +3986,7 @@
   }
 
   // Process attributes attached to the ivar.
-  ProcessDeclAttributes(NewID, D);
+  ProcessDeclAttributes(S, NewID, D);
   
   if (D.isInvalidType())
     NewID->setInvalidDecl();
@@ -4151,7 +4152,7 @@
   }
 
   if (Attr)
-    ProcessDeclAttributeList(Record, Attr);
+    ProcessDeclAttributeList(S, Record, Attr);
 }
 
 EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 1afdb60..b309b3b 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -156,8 +156,8 @@
 // least add some helper functions to check most argument patterns (#
 // and types of args).
 
-static void HandleExtVectorTypeAttr(Decl *d, const AttributeList &Attr,
-                                    Sema &S) {
+static void HandleExtVectorTypeAttr(Scope *scope, Decl *d, 
+                                    const AttributeList &Attr, Sema &S) {
   TypedefDecl *tDecl = dyn_cast<TypedefDecl>(d);
   if (tDecl == 0) {
     S.Diag(Attr.getLoc(), diag::err_typecheck_ext_vector_not_typedef);
@@ -165,37 +165,32 @@
   }
   
   QualType curType = tDecl->getUnderlyingType();
-  // check the attribute arguments.
-  if (Attr.getNumArgs() != 1) {
-    S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
-    return;
+
+  Expr *sizeExpr;
+
+  // Special case where the argument is a template id.
+  if (Attr.getParameterName()) {
+    sizeExpr = S.ActOnDeclarationNameExpr(scope, Attr.getLoc(),
+                               Attr.getParameterName(),
+                               false, 0, false).takeAs<Expr>();
+  } else {
+    // check the attribute arguments.
+    if (Attr.getNumArgs() != 1) {
+      S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+      return;
+    }
+    sizeExpr = static_cast<Expr *>(Attr.getArg(0));
   }
-  Expr *sizeExpr = static_cast<Expr *>(Attr.getArg(0));
-  llvm::APSInt vecSize(32);
-  if (!sizeExpr->isIntegerConstantExpr(vecSize, S.Context)) {
-    S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
-      << "ext_vector_type" << sizeExpr->getSourceRange();
-    return;
+
+  // Instantiate/Install the vector type, and let Sema build the type for us.
+  // This will run the reguired checks.
+  QualType T = S.BuildExtVectorType(curType, S.Owned(sizeExpr), Attr.getLoc());
+  if (!T.isNull()) {
+    tDecl->setUnderlyingType(T);
+    
+    // Remember this typedef decl, we will need it later for diagnostics.
+    S.ExtVectorDecls.push_back(tDecl);
   }
-  // unlike gcc's vector_size attribute, we do not allow vectors to be defined
-  // in conjunction with complex types (pointers, arrays, functions, etc.).
-  if (!curType->isIntegerType() && !curType->isRealFloatingType()) {
-    S.Diag(Attr.getLoc(), diag::err_attribute_invalid_vector_type) << curType;
-    return;
-  }
-  // unlike gcc's vector_size attribute, the size is specified as the 
-  // number of elements, not the number of bytes.
-  unsigned vectorSize = static_cast<unsigned>(vecSize.getZExtValue()); 
-  
-  if (vectorSize == 0) {
-    S.Diag(Attr.getLoc(), diag::err_attribute_zero_size)
-      << sizeExpr->getSourceRange();
-    return;
-  }
-  // Instantiate/Install the vector type, the number of elements is > 0.
-  tDecl->setUnderlyingType(S.Context.getExtVectorType(curType, vectorSize));
-  // Remember this typedef decl, we will need it later for diagnostics.
-  S.ExtVectorDecls.push_back(tDecl);
 }
 
 
@@ -1698,7 +1693,7 @@
 /// ProcessDeclAttribute - Apply the specific attribute to the specified decl if
 /// the attribute applies to decls.  If the attribute is a type attribute, just
 /// silently ignore it.
-static void ProcessDeclAttribute(Decl *D, const AttributeList &Attr, Sema &S) {
+static void ProcessDeclAttribute(Scope *scope, Decl *D, const AttributeList &Attr, Sema &S) {
   if (Attr.isDeclspecAttribute())
     // FIXME: Try to deal with __declspec attributes!
     return;
@@ -1721,7 +1716,7 @@
   case AttributeList::AT_dllexport:   HandleDLLExportAttr (D, Attr, S); break;
   case AttributeList::AT_dllimport:   HandleDLLImportAttr (D, Attr, S); break;
   case AttributeList::AT_ext_vector_type:
-    HandleExtVectorTypeAttr(D, Attr, S);
+    HandleExtVectorTypeAttr(scope, D, Attr, S);
     break;
   case AttributeList::AT_fastcall:    HandleFastCallAttr  (D, Attr, S); break;
   case AttributeList::AT_format:      HandleFormatAttr    (D, Attr, S); break;
@@ -1777,9 +1772,9 @@
 
 /// ProcessDeclAttributeList - Apply all the decl attributes in the specified
 /// attribute list to the specified decl, ignoring any type attributes.
-void Sema::ProcessDeclAttributeList(Decl *D, const AttributeList *AttrList) {
+void Sema::ProcessDeclAttributeList(Scope *S, Decl *D, const AttributeList *AttrList) {
   while (AttrList) {
-    ProcessDeclAttribute(D, *AttrList, *this);
+    ProcessDeclAttribute(S, D, *AttrList, *this);
     AttrList = AttrList->getNext();
   }
 }
@@ -1787,10 +1782,10 @@
 /// ProcessDeclAttributes - Given a declarator (PD) with attributes indicated in
 /// it, apply them to D.  This is a bit tricky because PD can have attributes
 /// specified in many different places, and we need to find and apply them all.
-void Sema::ProcessDeclAttributes(Decl *D, const Declarator &PD) {
+void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD) {
   // Apply decl attributes from the DeclSpec if present.
   if (const AttributeList *Attrs = PD.getDeclSpec().getAttributes())
-    ProcessDeclAttributeList(D, Attrs);
+    ProcessDeclAttributeList(S, D, Attrs);
   
   // Walk the declarator structure, applying decl attributes that were in a type
   // position to the decl itself.  This handles cases like:
@@ -1798,9 +1793,9 @@
   // when X is a decl attribute.
   for (unsigned i = 0, e = PD.getNumTypeObjects(); i != e; ++i)
     if (const AttributeList *Attrs = PD.getTypeObject(i).getAttrs())
-      ProcessDeclAttributeList(D, Attrs);
+      ProcessDeclAttributeList(S, D, Attrs);
   
   // Finally, apply any attributes on the decl itself.
   if (const AttributeList *Attrs = PD.getAttributes())
-    ProcessDeclAttributeList(D, Attrs);
+    ProcessDeclAttributeList(S, D, Attrs);
 }
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 70057a3..7a47894 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -2671,7 +2671,7 @@
   else
     CurContext->addDecl(Context, ExDecl);
 
-  ProcessDeclAttributes(ExDecl, D);
+  ProcessDeclAttributes(S, ExDecl, D);
   return DeclPtrTy::make(ExDecl);
 }
 
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index 5d47516..9013726 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -116,7 +116,7 @@
     IDecl = ObjCInterfaceDecl::Create(Context, CurContext, AtInterfaceLoc, 
                                       ClassName, ClassLoc);
     if (AttrList)
-      ProcessDeclAttributeList(IDecl, AttrList);
+      ProcessDeclAttributeList(TUScope, IDecl, AttrList);
   
     PushOnScopeChains(IDecl, TUScope);
   }
@@ -282,7 +282,7 @@
     PDecl->setForwardDecl(false);
   }
   if (AttrList)
-    ProcessDeclAttributeList(PDecl, AttrList);
+    ProcessDeclAttributeList(TUScope, PDecl, AttrList);
   if (NumProtoRefs) {
     /// Check then save referenced protocols.
     PDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs,Context);
@@ -532,7 +532,7 @@
       PushOnScopeChains(PDecl, TUScope);
     }
     if (attrList)
-      ProcessDeclAttributeList(PDecl, attrList);
+      ProcessDeclAttributeList(TUScope, PDecl, attrList);
     Protocols.push_back(PDecl);
   }
   
@@ -1663,7 +1663,7 @@
       CvtQTToAstBitMask(ArgInfo[i].DeclSpec.getObjCDeclQualifier()));
     
     // Apply the attributes to the parameter.
-    ProcessDeclAttributeList(Param, ArgInfo[i].ArgAttrs);
+    ProcessDeclAttributeList(TUScope, Param, ArgInfo[i].ArgAttrs);
     
     Params.push_back(Param);
   }
@@ -1674,7 +1674,7 @@
   const ObjCMethodDecl *PrevMethod = 0;
 
   if (AttrList)
-    ProcessDeclAttributeList(ObjCMethod, AttrList);
+    ProcessDeclAttributeList(TUScope, ObjCMethod, AttrList);
   
   // For implementations (which can be very "coarse grain"), we add the 
   // method now. This allows the AST to implement lookup methods that work 
@@ -1877,7 +1877,7 @@
     PDecl->setInvalidDecl();
   }
   
-  ProcessDeclAttributes(PDecl, FD.D);
+  ProcessDeclAttributes(S, PDecl, FD.D);
 
   // Regardless of setter/getter attribute, we save the default getter/setter
   // selector names in anticipation of declaration of setter/getter methods.
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index c046941..ab12cff 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -5126,7 +5126,7 @@
 
   if (ParamInfo.getNumTypeObjects() == 0
       || ParamInfo.getTypeObject(0).Kind != DeclaratorChunk::Function) {
-    ProcessDeclAttributes(CurBlock->TheDecl, ParamInfo);
+    ProcessDeclAttributes(CurScope, CurBlock->TheDecl, ParamInfo);
     QualType T = GetTypeForDeclarator(ParamInfo, CurScope);
 
     if (T->isArrayType()) {
@@ -5182,7 +5182,7 @@
   CurBlock->TheDecl->setParams(Context, CurBlock->Params.data(),
                                CurBlock->Params.size());
   CurBlock->TheDecl->setIsVariadic(CurBlock->isVariadic);
-  ProcessDeclAttributes(CurBlock->TheDecl, ParamInfo);
+  ProcessDeclAttributes(CurScope, CurBlock->TheDecl, ParamInfo);
   for (BlockDecl::param_iterator AI = CurBlock->TheDecl->param_begin(),
        E = CurBlock->TheDecl->param_end(); AI != E; ++AI)
     // If this has an identifier, add it to the scope stack.
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index d7a8a72..0ae9f1d 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -548,7 +548,7 @@
     NewClass->startDefinition();
 
   if (Attr)
-    ProcessDeclAttributeList(NewClass, Attr);
+    ProcessDeclAttributeList(S, NewClass, Attr);
 
   PushOnScopeChains(NewTemplate, S);
 
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index c9b6e13..dd955fe 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -802,6 +802,14 @@
                                   Deduced);
     break;
 
+  case Type::DependentSizedExtVector: {
+    const DependentSizedExtVectorType *VecType
+    = cast<DependentSizedExtVectorType>(T.getTypePtr());
+    MarkDeducedTemplateParameters(SemaRef, VecType->getElementType(), Deduced);
+    MarkDeducedTemplateParameters(VecType->getSizeExpr(), Deduced);
+    break;
+  }
+
   case Type::FunctionProto: {
     const FunctionProtoType *Proto = cast<FunctionProtoType>(T.getTypePtr());
     MarkDeducedTemplateParameters(SemaRef, Proto->getResultType(), Deduced);
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 31c048d..fd5a460 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -431,6 +431,32 @@
 }
 
 QualType 
+TemplateTypeInstantiator::
+InstantiateDependentSizedExtVectorType(const DependentSizedExtVectorType *T,
+                                   unsigned Quals) const {
+
+  // Instantiate the element type if needed
+  QualType ElementType = T->getElementType();
+  if (ElementType->isDependentType()) {
+    ElementType = Instantiate(ElementType);
+    if (ElementType.isNull())
+      return QualType();
+  }
+
+  // Instantiate the size expression
+  Expr *SizeExpr = T->getSizeExpr();
+  Sema::OwningExprResult InstantiatedArraySize = 
+    SemaRef.InstantiateExpr(SizeExpr, TemplateArgs);
+  if (InstantiatedArraySize.isInvalid())
+    return QualType();
+  
+  return SemaRef.BuildExtVectorType(ElementType,
+                                    SemaRef.Owned(
+                                      InstantiatedArraySize.takeAs<Expr>()),
+                                    T->getAttributeLoc());
+}
+
+QualType 
 TemplateTypeInstantiator::InstantiateVectorType(const VectorType *T,
                                              unsigned Quals) const {
   // FIXME: Implement this
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 70a9270..967f650 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -543,6 +543,48 @@
 
   return T;
 }
+
+/// \brief Build an ext-vector type.
+///
+/// Run the required checks for the extended vector type.
+QualType Sema::BuildExtVectorType(QualType T, ExprArg ArraySize, 
+                                  SourceLocation AttrLoc) {
+
+  Expr *Arg = (Expr *)ArraySize.get();
+
+  // unlike gcc's vector_size attribute, we do not allow vectors to be defined
+  // in conjunction with complex types (pointers, arrays, functions, etc.).
+  if (!T->isDependentType() && 
+      !T->isIntegerType() && !T->isRealFloatingType()) {
+    Diag(AttrLoc, diag::err_attribute_invalid_vector_type) << T;
+    return QualType();
+  }
+
+  if (!Arg->isTypeDependent() && !Arg->isValueDependent()) {
+    llvm::APSInt vecSize(32);
+    if (!Arg->isIntegerConstantExpr(vecSize, Context)) {
+      Diag(AttrLoc, diag::err_attribute_argument_not_int)
+      << "ext_vector_type" << Arg->getSourceRange();
+      return QualType();
+    }
+    
+    // unlike gcc's vector_size attribute, the size is specified as the 
+    // number of elements, not the number of bytes.
+    unsigned vectorSize = static_cast<unsigned>(vecSize.getZExtValue()); 
+    
+    if (vectorSize == 0) {
+      Diag(AttrLoc, diag::err_attribute_zero_size)
+      << Arg->getSourceRange();
+      return QualType();
+    }
+    
+    if (!T->isDependentType())
+      return Context.getExtVectorType(T, vectorSize);
+  } 
+  
+  return Context.getDependentSizedExtVectorType(T, ArraySize.takeAs<Expr>(), 
+                                                AttrLoc);
+}
                               
 /// \brief Build a function type.
 ///