From: Douglas Gregor Date: Wed, 15 Jun 2011 16:02:29 +0000 (+0000) Subject: Eliminate a 'default' case in template argument deduction, where we X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=4ac01401b1ec602a1f58c217544d3dcb5fcbd7f1;p=clang Eliminate a 'default' case in template argument deduction, where we 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 --- diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 6dd0d3ceab..4ddc80a72d 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -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. diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 9094abad2e..4c66ed8d7e 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -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; diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 1ec7199562..430b4f99fb 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -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(); + + 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) { diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index 842c5fb17d..9011cdf753 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -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()) + return DeduceTemplateArguments(S, TemplateParams, + cast(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()))) + case Type::ExtVector: { + const ExtVectorType *VectorParam = cast(Param); + if (const ExtVectorType *VectorArg = dyn_cast(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(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(Param); + + if (const ExtVectorType *VectorArg = dyn_cast(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(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). diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index ec8fdc917c..ef3c2624b2 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -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"); diff --git a/test/SemaTemplate/ext-vector-type.cpp b/test/SemaTemplate/ext-vector-type.cpp index 7334e88e92..f968c13f10 100644 --- a/test/SemaTemplate/ext-vector-type.cpp +++ b/test/SemaTemplate/ext-vector-type.cpp @@ -58,3 +58,37 @@ int test_make6() { y.x = -1; y.w = -1; // expected-error{{vector component access exceeds type}} } + +namespace Deduction { + template struct X0; + + template + struct X0 { + static const unsigned value = 0; + }; + + template + struct X0 { + static const unsigned value = 1; + }; + + template + struct X0 { + static const unsigned value = 2; + }; + + template<> + struct X0 { + 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::value == 0? 1 : -1]; + int array1[X0::value == 1? 1 : -1]; + int array2[X0::value == 2? 1 : -1]; + int array3[X0::value == 3? 1 : -1]; +}