Author: rsmith Date: Thu Jan 26 14:40:47 2017 New Revision: 293207 URL: http://llvm.org/viewvc/llvm-project?rev=293207&view=rev Log: PR0091R3: Implement parsing support for using templates as types.
This change adds a new type node, DeducedTemplateSpecializationType, to represent a type template name that has been used as a type. This is modeled around AutoType, and shares a common base class for representing a deduced placeholder type. We allow deduced class template types in a few more places than the standard does: in conditions and for-range-declarators, and in new-type-ids. This is consistent with GCC and with discussion on the core reflector. This patch does not yet support deduced class template types being named in typename specifiers. Added: cfe/trunk/test/Parser/cxx1z-class-template-argument-deduction.cpp Modified: cfe/trunk/include/clang/AST/ASTContext.h cfe/trunk/include/clang/AST/RecursiveASTVisitor.h cfe/trunk/include/clang/AST/Type.h cfe/trunk/include/clang/AST/TypeLoc.h cfe/trunk/include/clang/AST/TypeNodes.def cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td cfe/trunk/include/clang/Parse/Parser.h cfe/trunk/include/clang/Sema/DeclSpec.h cfe/trunk/include/clang/Sema/Sema.h cfe/trunk/include/clang/Serialization/ASTBitCodes.h cfe/trunk/lib/AST/ASTContext.cpp cfe/trunk/lib/AST/ASTImporter.cpp cfe/trunk/lib/AST/ExprConstant.cpp cfe/trunk/lib/AST/ItaniumMangle.cpp cfe/trunk/lib/AST/MicrosoftMangle.cpp cfe/trunk/lib/AST/Type.cpp cfe/trunk/lib/AST/TypePrinter.cpp cfe/trunk/lib/CodeGen/CGDebugInfo.cpp cfe/trunk/lib/CodeGen/CodeGenFunction.cpp cfe/trunk/lib/CodeGen/CodeGenTypes.cpp cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp cfe/trunk/lib/Parse/ParseDecl.cpp cfe/trunk/lib/Parse/ParseDeclCXX.cpp cfe/trunk/lib/Parse/ParseExprCXX.cpp cfe/trunk/lib/Parse/Parser.cpp cfe/trunk/lib/Sema/SemaDecl.cpp cfe/trunk/lib/Sema/SemaExpr.cpp cfe/trunk/lib/Sema/SemaExprCXX.cpp cfe/trunk/lib/Sema/SemaLookup.cpp cfe/trunk/lib/Sema/SemaTemplate.cpp cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp cfe/trunk/lib/Sema/SemaType.cpp cfe/trunk/lib/Sema/TreeTransform.h cfe/trunk/lib/Serialization/ASTReader.cpp cfe/trunk/lib/Serialization/ASTWriter.cpp cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp cfe/trunk/test/CXX/drs/dr5xx.cpp cfe/trunk/test/Parser/backtrack-off-by-one.cpp cfe/trunk/test/SemaTemplate/temp_arg.cpp cfe/trunk/test/SemaTemplate/typename-specifier-3.cpp cfe/trunk/tools/libclang/CIndex.cpp cfe/trunk/tools/libclang/CXType.cpp Modified: cfe/trunk/include/clang/AST/ASTContext.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=293207&r1=293206&r2=293207&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/ASTContext.h (original) +++ cfe/trunk/include/clang/AST/ASTContext.h Thu Jan 26 14:40:47 2017 @@ -167,6 +167,8 @@ class ASTContext : public RefCountedBase mutable llvm::FoldingSet<DependentUnaryTransformType> DependentUnaryTransformTypes; mutable llvm::FoldingSet<AutoType> AutoTypes; + mutable llvm::FoldingSet<DeducedTemplateSpecializationType> + DeducedTemplateSpecializationTypes; mutable llvm::FoldingSet<AtomicType> AtomicTypes; llvm::FoldingSet<AttributedType> AttributedTypes; mutable llvm::FoldingSet<PipeType> PipeTypes; @@ -1412,6 +1414,11 @@ public: /// \brief C++11 deduction pattern for 'auto &&' type. QualType getAutoRRefDeductType() const; + /// \brief C++1z deduced class template specialization type. + QualType getDeducedTemplateSpecializationType(TemplateName Template, + QualType DeducedType, + bool IsDependent) const; + /// \brief Return the unique reference to the type for the specified TagDecl /// (struct/union/class/enum) decl. QualType getTagDeclType(const TagDecl *Decl) const; Modified: cfe/trunk/include/clang/AST/RecursiveASTVisitor.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/RecursiveASTVisitor.h?rev=293207&r1=293206&r2=293207&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/RecursiveASTVisitor.h (original) +++ cfe/trunk/include/clang/AST/RecursiveASTVisitor.h Thu Jan 26 14:40:47 2017 @@ -1008,6 +1008,10 @@ DEF_TRAVERSE_TYPE(UnaryTransformType, { }) DEF_TRAVERSE_TYPE(AutoType, { TRY_TO(TraverseType(T->getDeducedType())); }) +DEF_TRAVERSE_TYPE(DeducedTemplateSpecializationType, { + TRY_TO(TraverseTemplateName(T->getTemplateName())); + TRY_TO(TraverseType(T->getDeducedType())); +}) DEF_TRAVERSE_TYPE(RecordType, {}) DEF_TRAVERSE_TYPE(EnumType, {}) @@ -1232,6 +1236,11 @@ DEF_TRAVERSE_TYPELOC(AutoType, { TRY_TO(TraverseType(TL.getTypePtr()->getDeducedType())); }) +DEF_TRAVERSE_TYPELOC(DeducedTemplateSpecializationType, { + TRY_TO(TraverseTemplateName(TL.getTypePtr()->getTemplateName())); + TRY_TO(TraverseType(TL.getTypePtr()->getDeducedType())); +}) + DEF_TRAVERSE_TYPELOC(RecordType, {}) DEF_TRAVERSE_TYPELOC(EnumType, {}) DEF_TRAVERSE_TYPELOC(TemplateTypeParmType, {}) Modified: cfe/trunk/include/clang/AST/Type.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=293207&r1=293206&r2=293207&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/Type.h (original) +++ cfe/trunk/include/clang/AST/Type.h Thu Jan 26 14:40:47 2017 @@ -1785,7 +1785,8 @@ public: } /// \brief Determine whether this type is an undeduced type, meaning that - /// it somehow involves a C++11 'auto' type which has not yet been deduced. + /// it somehow involves a C++11 'auto' type or similar which has not yet been + /// deduced. bool isUndeducedType() const; /// \brief Whether this type is a variably-modified type (C99 6.7.5). @@ -1862,10 +1863,17 @@ public: /// not refer to a CXXRecordDecl, returns NULL. const CXXRecordDecl *getPointeeCXXRecordDecl() const; + /// Get the DeducedType whose type will be deduced for a variable with + /// an initializer of this type. This looks through declarators like pointer + /// types, but not through decltype or typedefs. + DeducedType *getContainedDeducedType() const; + /// Get the AutoType whose type will be deduced for a variable with /// an initializer of this type. This looks through declarators like pointer /// types, but not through decltype or typedefs. - AutoType *getContainedAutoType() const; + AutoType *getContainedAutoType() const { + return dyn_cast_or_null<AutoType>(getContainedDeducedType()); + } /// Determine whether this type was written with a leading 'auto' /// corresponding to a trailing return type (possibly for a nested @@ -4094,43 +4102,38 @@ public: } }; -/// \brief Represents a C++11 auto or C++14 decltype(auto) type. +/// \brief Common base class for placeholders for types that get replaced by +/// placeholder type deduction: C++11 auto, C++14 decltype(auto), C++17 deduced +/// class template types, and (eventually) constrained type names from the C++ +/// Concepts TS. /// /// These types are usually a placeholder for a deduced type. However, before /// the initializer is attached, or (usually) if the initializer is -/// type-dependent, there is no deduced type and an auto type is canonical. In +/// type-dependent, there is no deduced type and the type is canonical. In /// the latter case, it is also a dependent type. -class AutoType : public Type, public llvm::FoldingSetNode { - AutoType(QualType DeducedType, AutoTypeKeyword Keyword, bool IsDependent) - : Type(Auto, DeducedType.isNull() ? QualType(this, 0) : DeducedType, - /*Dependent=*/IsDependent, /*InstantiationDependent=*/IsDependent, - /*VariablyModified=*/false, /*ContainsParameterPack=*/false) { - if (!DeducedType.isNull()) { - if (DeducedType->isDependentType()) +class DeducedType : public Type { +protected: + DeducedType(TypeClass TC, QualType DeducedAsType, bool IsDependent, + bool IsInstantiationDependent, bool ContainsParameterPack) + : Type(TC, DeducedAsType.isNull() ? QualType(this, 0) : DeducedAsType, + IsDependent, IsInstantiationDependent, + /*VariablyModified=*/false, ContainsParameterPack) { + if (!DeducedAsType.isNull()) { + if (DeducedAsType->isDependentType()) setDependent(); - if (DeducedType->isInstantiationDependentType()) + if (DeducedAsType->isInstantiationDependentType()) setInstantiationDependent(); - if (DeducedType->containsUnexpandedParameterPack()) + if (DeducedAsType->containsUnexpandedParameterPack()) setContainsUnexpandedParameterPack(); } - AutoTypeBits.Keyword = (unsigned)Keyword; } - friend class ASTContext; // ASTContext creates these - public: - bool isDecltypeAuto() const { - return getKeyword() == AutoTypeKeyword::DecltypeAuto; - } - AutoTypeKeyword getKeyword() const { - return (AutoTypeKeyword)AutoTypeBits.Keyword; - } - bool isSugared() const { return !isCanonicalUnqualified(); } QualType desugar() const { return getCanonicalTypeInternal(); } - /// \brief Get the type deduced for this auto type, or null if it's either - /// not been deduced or was deduced to a dependent type. + /// \brief Get the type deduced for this placeholder type, or null if it's + /// either not been deduced or was deduced to a dependent type. QualType getDeducedType() const { return !isCanonicalUnqualified() ? getCanonicalTypeInternal() : QualType(); } @@ -4138,6 +4141,31 @@ public: return !isCanonicalUnqualified() || isDependentType(); } + static bool classof(const Type *T) { + return T->getTypeClass() == Auto || + T->getTypeClass() == DeducedTemplateSpecialization; + } +}; + +/// \brief Represents a C++11 auto or C++14 decltype(auto) type. +class AutoType : public DeducedType, public llvm::FoldingSetNode { + AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword, + bool IsDeducedAsDependent) + : DeducedType(Auto, DeducedAsType, IsDeducedAsDependent, + IsDeducedAsDependent, /*ContainsPack=*/false) { + AutoTypeBits.Keyword = (unsigned)Keyword; + } + + friend class ASTContext; // ASTContext creates these + +public: + bool isDecltypeAuto() const { + return getKeyword() == AutoTypeKeyword::DecltypeAuto; + } + AutoTypeKeyword getKeyword() const { + return (AutoTypeKeyword)AutoTypeBits.Keyword; + } + void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, getDeducedType(), getKeyword(), isDependentType()); } @@ -4154,6 +4182,43 @@ public: } }; +/// \brief Represents a C++17 deduced template specialization type. +class DeducedTemplateSpecializationType : public DeducedType, + public llvm::FoldingSetNode { + /// The name of the template whose arguments will be deduced. + TemplateName Template; + + DeducedTemplateSpecializationType(TemplateName Template, + QualType DeducedAsType, + bool IsDeducedAsDependent) + : DeducedType(DeducedTemplateSpecialization, DeducedAsType, + IsDeducedAsDependent || Template.isDependent(), + IsDeducedAsDependent || Template.isInstantiationDependent(), + Template.containsUnexpandedParameterPack()), + Template(Template) {} + + friend class ASTContext; // ASTContext creates these + +public: + /// Retrieve the name of the template that we are deducing. + TemplateName getTemplateName() const { return Template;} + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getTemplateName(), getDeducedType(), isDependentType()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, TemplateName Template, + QualType Deduced, bool IsDependent) { + Template.Profile(ID); + ID.AddPointer(Deduced.getAsOpaquePtr()); + ID.AddBoolean(IsDependent); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == DeducedTemplateSpecialization; + } +}; + /// \brief Represents a type template specialization; the template /// must be a class template, a type alias template, or a template /// template parameter. A template which cannot be resolved to one of @@ -5857,8 +5922,8 @@ inline bool Type::isBooleanType() const } inline bool Type::isUndeducedType() const { - const AutoType *AT = getContainedAutoType(); - return AT && !AT->isDeduced(); + auto *DT = getContainedDeducedType(); + return DT && !DT->isDeduced(); } /// \brief Determines whether this is a type for which one can define Modified: cfe/trunk/include/clang/AST/TypeLoc.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/TypeLoc.h?rev=293207&r1=293206&r2=293207&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/TypeLoc.h (original) +++ cfe/trunk/include/clang/AST/TypeLoc.h Thu Jan 26 14:40:47 2017 @@ -1827,9 +1827,25 @@ public: } }; -class AutoTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc, - AutoTypeLoc, - AutoType> { +class DeducedTypeLoc + : public InheritingConcreteTypeLoc<TypeSpecTypeLoc, DeducedTypeLoc, + DeducedType> {}; + +class AutoTypeLoc + : public InheritingConcreteTypeLoc<DeducedTypeLoc, AutoTypeLoc, AutoType> { +}; + +class DeducedTemplateSpecializationTypeLoc + : public InheritingConcreteTypeLoc<DeducedTypeLoc, + DeducedTemplateSpecializationTypeLoc, + DeducedTemplateSpecializationType> { +public: + SourceLocation getTemplateNameLoc() const { + return getNameLoc(); + } + void setTemplateNameLoc(SourceLocation Loc) { + setNameLoc(Loc); + } }; struct ElaboratedLocInfo { Modified: cfe/trunk/include/clang/AST/TypeNodes.def URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/TypeNodes.def?rev=293207&r1=293206&r2=293207&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/TypeNodes.def (original) +++ cfe/trunk/include/clang/AST/TypeNodes.def Thu Jan 26 14:40:47 2017 @@ -96,7 +96,9 @@ DEPENDENT_TYPE(TemplateTypeParm, Type) NON_CANONICAL_TYPE(SubstTemplateTypeParm, Type) DEPENDENT_TYPE(SubstTemplateTypeParmPack, Type) NON_CANONICAL_UNLESS_DEPENDENT_TYPE(TemplateSpecialization, Type) -TYPE(Auto, Type) +ABSTRACT_TYPE(Deduced, Type) +TYPE(Auto, DeducedType) +TYPE(DeducedTemplateSpecialization, DeducedType) DEPENDENT_TYPE(InjectedClassName, Type) DEPENDENT_TYPE(DependentName, Type) DEPENDENT_TYPE(DependentTemplateSpecialization, Type) Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=293207&r1=293206&r2=293207&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Jan 26 14:40:47 2017 @@ -1870,16 +1870,20 @@ def err_illegal_decl_array_of_auto : Err def err_new_array_of_auto : Error< "cannot allocate array of 'auto'">; def err_auto_not_allowed : Error< - "%select{'auto'|'decltype(auto)'|'__auto_type'}0 not allowed " + "%select{'auto'|'decltype(auto)'|'__auto_type'|" + "use of " + "%select{class template|function template|variable template|alias template|" + "template template parameter|template}2 %3 requires template arguments; " + "argument deduction}0 not allowed " "%select{in function prototype" "|in non-static struct member|in struct member" "|in non-static union member|in union member" "|in non-static class member|in interface member" - "|in exception declaration|in template parameter|in block literal" + "|in exception declaration|in template parameter until C++1z|in block literal" "|in template argument|in typedef|in type alias|in function return type" "|in conversion function type|here|in lambda parameter" - "|in type allocated by 'new'|in K&R-style function parameter}1" - "%select{|||||||| until C++1z||||||||||}1">; + "|in type allocated by 'new'|in K&R-style function parameter" + "|in template parameter|in friend declaration}1">; def err_auto_not_allowed_var_inst : Error< "'auto' variable template instantiation is not allowed">; def err_auto_var_requires_init : Error< @@ -1944,6 +1948,14 @@ def err_decltype_auto_compound_type : Er def err_decltype_auto_initializer_list : Error< "cannot deduce 'decltype(auto)' from initializer list">; +// C++1z deduced class template specialization types +def err_deduced_class_template_compound_type : Error< + "cannot %select{form pointer to|form reference to|form array of|" + "form function returning|use parentheses when declaring variable with}0 " + "deduced class template specialization type">; +def err_deduced_class_template_not_supported : Error< + "deduction of template arguments for class templates is not yet supported">; + // C++1y deduced return types def err_auto_fn_deduction_failure : Error< "cannot deduce return type %0 from returned value of type %1">; Modified: cfe/trunk/include/clang/Parse/Parser.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=293207&r1=293206&r2=293207&view=diff ============================================================================== --- cfe/trunk/include/clang/Parse/Parser.h (original) +++ cfe/trunk/include/clang/Parse/Parser.h Thu Jan 26 14:40:47 2017 @@ -1834,6 +1834,26 @@ private: llvm_unreachable("Missing DeclSpecContext case"); } + /// Is this a context in which we can perform class template argument + /// deduction? + static bool isClassTemplateDeductionContext(DeclSpecContext DSC) { + switch (DSC) { + case DSC_normal: + case DSC_class: + case DSC_top_level: + case DSC_condition: + case DSC_type_specifier: + return true; + + case DSC_objc_method_result: + case DSC_template_type_arg: + case DSC_trailing: + case DSC_alias_declaration: + return false; + } + llvm_unreachable("Missing DeclSpecContext case"); + } + /// Information on a C++0x for-range-initializer found while parsing a /// declaration which turns out to be a for-range-declaration. struct ForRangeInit { Modified: cfe/trunk/include/clang/Sema/DeclSpec.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/DeclSpec.h?rev=293207&r1=293206&r2=293207&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/DeclSpec.h (original) +++ cfe/trunk/include/clang/Sema/DeclSpec.h Thu Jan 26 14:40:47 2017 @@ -1709,6 +1709,7 @@ public: ObjCParameterContext,// An ObjC method parameter type. KNRTypeListContext, // K&R type definition list for formals. TypeNameContext, // Abstract declarator for types. + FunctionalCastContext, // Type in a C++ functional cast expression. MemberContext, // Struct/Union field. BlockContext, // Declaration within a block in a function. ForContext, // Declaration within first part of a for loop. @@ -1911,6 +1912,7 @@ public: return false; case TypeNameContext: + case FunctionalCastContext: case AliasDeclContext: case AliasTemplateContext: case PrototypeContext: @@ -1951,6 +1953,7 @@ public: return true; case TypeNameContext: + case FunctionalCastContext: case CXXNewContext: case AliasDeclContext: case AliasTemplateContext: @@ -1983,6 +1986,7 @@ public: case CXXCatchContext: case ObjCCatchContext: case TypeNameContext: + case FunctionalCastContext: case ConversionIdContext: case ObjCParameterContext: case ObjCResultContext: @@ -2021,6 +2025,7 @@ public: // These contexts don't allow any kind of non-abstract declarator. case KNRTypeListContext: case TypeNameContext: + case FunctionalCastContext: case AliasDeclContext: case AliasTemplateContext: case LambdaExprParameterContext: @@ -2078,6 +2083,7 @@ public: case CXXCatchContext: case ObjCCatchContext: case TypeNameContext: + case FunctionalCastContext: // FIXME case CXXNewContext: case AliasDeclContext: case AliasTemplateContext: @@ -2279,6 +2285,7 @@ public: case ConditionContext: case KNRTypeListContext: case TypeNameContext: + case FunctionalCastContext: case AliasDeclContext: case AliasTemplateContext: case PrototypeContext: Modified: cfe/trunk/include/clang/Sema/Sema.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=293207&r1=293206&r2=293207&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/Sema.h (original) +++ cfe/trunk/include/clang/Sema/Sema.h Thu Jan 26 14:40:47 2017 @@ -1548,6 +1548,7 @@ public: ParsedType ObjectType = nullptr, bool IsCtorOrDtorName = false, bool WantNontrivialTypeSourceInfo = false, + bool IsClassTemplateDeductionContext = true, IdentifierInfo **CorrectedII = nullptr); TypeSpecifierType isTagName(IdentifierInfo &II, Scope *S); bool isMicrosoftMissingTypename(const CXXScopeSpec *SS, Scope *S); Modified: cfe/trunk/include/clang/Serialization/ASTBitCodes.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTBitCodes.h?rev=293207&r1=293206&r2=293207&view=diff ============================================================================== --- cfe/trunk/include/clang/Serialization/ASTBitCodes.h (original) +++ cfe/trunk/include/clang/Serialization/ASTBitCodes.h Thu Jan 26 14:40:47 2017 @@ -914,7 +914,9 @@ namespace clang { /// \brief A PipeType record. TYPE_PIPE = 43, /// \brief An ObjCTypeParamType record. - TYPE_OBJC_TYPE_PARAM = 44 + TYPE_OBJC_TYPE_PARAM = 44, + /// \brief A DeducedTemplateSpecializationType record. + TYPE_DEDUCED_TEMPLATE_SPECIALIZATION = 45 }; /// \brief The type IDs for special types constructed by semantic Modified: cfe/trunk/lib/AST/ASTContext.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=293207&r1=293206&r2=293207&view=diff ============================================================================== --- cfe/trunk/lib/AST/ASTContext.cpp (original) +++ cfe/trunk/lib/AST/ASTContext.cpp Thu Jan 26 14:40:47 2017 @@ -1877,8 +1877,9 @@ TypeInfo ASTContext::getTypeInfoImpl(con return getTypeInfo(cast<SubstTemplateTypeParmType>(T)-> getReplacementType().getTypePtr()); - case Type::Auto: { - const AutoType *A = cast<AutoType>(T); + case Type::Auto: + case Type::DeducedTemplateSpecialization: { + const DeducedType *A = cast<DeducedType>(T); assert(!A->getDeducedType().isNull() && "cannot request the size of an undeduced or dependent auto type"); return getTypeInfo(A->getDeducedType().getTypePtr()); @@ -2765,6 +2766,7 @@ QualType ASTContext::getVariableArrayDec case Type::TemplateTypeParm: case Type::SubstTemplateTypeParmPack: case Type::Auto: + case Type::DeducedTemplateSpecialization: case Type::PackExpansion: llvm_unreachable("type should never be variably-modified"); @@ -4435,6 +4437,28 @@ QualType ASTContext::getAutoType(QualTyp return QualType(AT, 0); } +/// Return the uniqued reference to the deduced template specialization type +/// which has been deduced to the given type, or to the canonical undeduced +/// such type, or the canonical deduced-but-dependent such type. +QualType ASTContext::getDeducedTemplateSpecializationType( + TemplateName Template, QualType DeducedType, bool IsDependent) const { + // Look in the folding set for an existing type. + void *InsertPos = nullptr; + llvm::FoldingSetNodeID ID; + DeducedTemplateSpecializationType::Profile(ID, Template, DeducedType, + IsDependent); + if (DeducedTemplateSpecializationType *DTST = + DeducedTemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(DTST, 0); + + DeducedTemplateSpecializationType *DTST = new (*this, TypeAlignment) + DeducedTemplateSpecializationType(Template, DeducedType, IsDependent); + Types.push_back(DTST); + if (InsertPos) + DeducedTemplateSpecializationTypes.InsertNode(DTST, InsertPos); + return QualType(DTST, 0); +} + /// getAtomicType - Return the uniqued reference to the atomic type for /// the given value type. QualType ASTContext::getAtomicType(QualType T) const { @@ -6333,6 +6357,7 @@ void ASTContext::getObjCEncodingForTypeI // We could see an undeduced auto type here during error recovery. // Just ignore it. case Type::Auto: + case Type::DeducedTemplateSpecialization: return; case Type::Pipe: @@ -8132,6 +8157,7 @@ QualType ASTContext::mergeTypes(QualType llvm_unreachable("Non-canonical and dependent types shouldn't get here"); case Type::Auto: + case Type::DeducedTemplateSpecialization: case Type::LValueReference: case Type::RValueReference: case Type::MemberPointer: Modified: cfe/trunk/lib/AST/ASTImporter.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTImporter.cpp?rev=293207&r1=293206&r2=293207&view=diff ============================================================================== --- cfe/trunk/lib/AST/ASTImporter.cpp (original) +++ cfe/trunk/lib/AST/ASTImporter.cpp Thu Jan 26 14:40:47 2017 @@ -883,6 +883,20 @@ static bool IsStructurallyEquivalent(Str return false; break; + case Type::DeducedTemplateSpecialization: { + auto *DT1 = cast<DeducedTemplateSpecializationType>(T1); + auto *DT2 = cast<DeducedTemplateSpecializationType>(T2); + if (!IsStructurallyEquivalent(Context, + DT1->getTemplateName(), + DT2->getTemplateName())) + return false; + if (!IsStructurallyEquivalent(Context, + DT1->getDeducedType(), + DT2->getDeducedType())) + return false; + break; + } + case Type::Record: case Type::Enum: if (!IsStructurallyEquivalent(Context, Modified: cfe/trunk/lib/AST/ExprConstant.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=293207&r1=293206&r2=293207&view=diff ============================================================================== --- cfe/trunk/lib/AST/ExprConstant.cpp (original) +++ cfe/trunk/lib/AST/ExprConstant.cpp Thu Jan 26 14:40:47 2017 @@ -7004,6 +7004,7 @@ static int EvaluateBuiltinClassifyType(c case Type::Vector: case Type::ExtVector: case Type::Auto: + case Type::DeducedTemplateSpecialization: case Type::ObjCObject: case Type::ObjCInterface: case Type::ObjCObjectPointer: Modified: cfe/trunk/lib/AST/ItaniumMangle.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ItaniumMangle.cpp?rev=293207&r1=293206&r2=293207&view=diff ============================================================================== --- cfe/trunk/lib/AST/ItaniumMangle.cpp (original) +++ cfe/trunk/lib/AST/ItaniumMangle.cpp Thu Jan 26 14:40:47 2017 @@ -1870,6 +1870,7 @@ bool CXXNameMangler::mangleUnresolvedTyp case Type::Paren: case Type::Attributed: case Type::Auto: + case Type::DeducedTemplateSpecialization: case Type::PackExpansion: case Type::ObjCObject: case Type::ObjCInterface: @@ -3145,6 +3146,16 @@ void CXXNameMangler::mangleType(const Au mangleType(D); } +void CXXNameMangler::mangleType(const DeducedTemplateSpecializationType *T) { + // FIXME: This is not the right mangling. We also need to include a scope + // here in some cases. + QualType D = T->getDeducedType(); + if (D.isNull()) + mangleUnscopedTemplateName(T->getTemplateName(), nullptr); + else + mangleType(D); +} + void CXXNameMangler::mangleType(const AtomicType *T) { // <type> ::= U <source-name> <type> # vendor extended type qualifier // (Until there's a standardized mangling...) Modified: cfe/trunk/lib/AST/MicrosoftMangle.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/MicrosoftMangle.cpp?rev=293207&r1=293206&r2=293207&view=diff ============================================================================== --- cfe/trunk/lib/AST/MicrosoftMangle.cpp (original) +++ cfe/trunk/lib/AST/MicrosoftMangle.cpp Thu Jan 26 14:40:47 2017 @@ -2474,6 +2474,17 @@ void MicrosoftCXXNameMangler::mangleType << Range; } +void MicrosoftCXXNameMangler::mangleType( + const DeducedTemplateSpecializationType *T, Qualifiers, SourceRange Range) { + assert(T->getDeducedType().isNull() && "expecting a dependent type!"); + + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, + "cannot mangle this deduced class template specialization type yet"); + Diags.Report(Range.getBegin(), DiagID) + << Range; +} + void MicrosoftCXXNameMangler::mangleType(const AtomicType *T, Qualifiers, SourceRange Range) { QualType ValueType = T->getValueType(); Modified: cfe/trunk/lib/AST/Type.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=293207&r1=293206&r2=293207&view=diff ============================================================================== --- cfe/trunk/lib/AST/Type.cpp (original) +++ cfe/trunk/lib/AST/Type.cpp Thu Jan 26 14:40:47 2017 @@ -1559,25 +1559,29 @@ TagDecl *Type::getAsTagDecl() const { } namespace { - class GetContainedAutoVisitor : - public TypeVisitor<GetContainedAutoVisitor, Type*> { + class GetContainedDeducedTypeVisitor : + public TypeVisitor<GetContainedDeducedTypeVisitor, Type*> { bool Syntactic; public: - GetContainedAutoVisitor(bool Syntactic = false) : Syntactic(Syntactic) {} + GetContainedDeducedTypeVisitor(bool Syntactic = false) + : Syntactic(Syntactic) {} - using TypeVisitor<GetContainedAutoVisitor, Type*>::Visit; + using TypeVisitor<GetContainedDeducedTypeVisitor, Type*>::Visit; Type *Visit(QualType T) { if (T.isNull()) return nullptr; return Visit(T.getTypePtr()); } - // The 'auto' type itself. - Type *VisitAutoType(const AutoType *AT) { - return const_cast<AutoType*>(AT); + // The deduced type itself. + Type *VisitDeducedType(const DeducedType *AT) { + return const_cast<DeducedType*>(AT); } // Only these types can contain the desired 'auto' type. + Type *VisitElaboratedType(const ElaboratedType *T) { + return Visit(T->getNamedType()); + } Type *VisitPointerType(const PointerType *T) { return Visit(T->getPointeeType()); } @@ -1620,13 +1624,14 @@ namespace { }; } -AutoType *Type::getContainedAutoType() const { - return cast_or_null<AutoType>(GetContainedAutoVisitor().Visit(this)); +DeducedType *Type::getContainedDeducedType() const { + return cast_or_null<DeducedType>( + GetContainedDeducedTypeVisitor().Visit(this)); } bool Type::hasAutoForTrailingReturnType() const { return dyn_cast_or_null<FunctionType>( - GetContainedAutoVisitor(true).Visit(this)); + GetContainedDeducedTypeVisitor(true).Visit(this)); } bool Type::hasIntegerRepresentation() const { @@ -3378,6 +3383,7 @@ static CachedProperties computeCachedPro return CachedProperties(ExternalLinkage, false); case Type::Auto: + case Type::DeducedTemplateSpecialization: // Give non-deduced 'auto' types external linkage. We should only see them // here in error recovery. return CachedProperties(ExternalLinkage, false); @@ -3485,6 +3491,7 @@ static LinkageInfo computeLinkageInfo(co return LinkageInfo::external(); case Type::Auto: + case Type::DeducedTemplateSpecialization: return LinkageInfo::external(); case Type::Record: @@ -3621,7 +3628,8 @@ bool Type::canHaveNullability() const { // auto is considered dependent when it isn't deduced. case Type::Auto: - return !cast<AutoType>(type.getTypePtr())->isDeduced(); + case Type::DeducedTemplateSpecialization: + return !cast<DeducedType>(type.getTypePtr())->isDeduced(); case Type::Builtin: switch (cast<BuiltinType>(type.getTypePtr())->getKind()) { Modified: cfe/trunk/lib/AST/TypePrinter.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/TypePrinter.cpp?rev=293207&r1=293206&r2=293207&view=diff ============================================================================== --- cfe/trunk/lib/AST/TypePrinter.cpp (original) +++ cfe/trunk/lib/AST/TypePrinter.cpp Thu Jan 26 14:40:47 2017 @@ -189,6 +189,7 @@ bool TypePrinter::canPrefixQualifiers(co case Type::Elaborated: case Type::TemplateTypeParm: case Type::SubstTemplateTypeParmPack: + case Type::DeducedTemplateSpecialization: case Type::TemplateSpecialization: case Type::InjectedClassName: case Type::DependentName: @@ -887,6 +888,24 @@ void TypePrinter::printAutoAfter(const A if (!T->getDeducedType().isNull()) printAfter(T->getDeducedType(), OS); } + +void TypePrinter::printDeducedTemplateSpecializationBefore( + const DeducedTemplateSpecializationType *T, raw_ostream &OS) { + // If the type has been deduced, print the deduced type. + if (!T->getDeducedType().isNull()) { + printBefore(T->getDeducedType(), OS); + } else { + IncludeStrongLifetimeRAII Strong(Policy); + T->getTemplateName().print(OS, Policy); + spaceBeforePlaceHolder(OS); + } +} +void TypePrinter::printDeducedTemplateSpecializationAfter( + const DeducedTemplateSpecializationType *T, raw_ostream &OS) { + // If the type has been deduced, print the deduced type. + if (!T->getDeducedType().isNull()) + printAfter(T->getDeducedType(), OS); +} void TypePrinter::printAtomicBefore(const AtomicType *T, raw_ostream &OS) { IncludeStrongLifetimeRAII Strong(Policy); Modified: cfe/trunk/lib/CodeGen/CGDebugInfo.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDebugInfo.cpp?rev=293207&r1=293206&r2=293207&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGDebugInfo.cpp (original) +++ cfe/trunk/lib/CodeGen/CGDebugInfo.cpp Thu Jan 26 14:40:47 2017 @@ -2618,6 +2618,7 @@ llvm::DIType *CGDebugInfo::CreateTypeNod case Type::Attributed: case Type::Adjusted: case Type::Decayed: + case Type::DeducedTemplateSpecialization: case Type::Elaborated: case Type::Paren: case Type::SubstTemplateTypeParm: Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.cpp?rev=293207&r1=293206&r2=293207&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CodeGenFunction.cpp (original) +++ cfe/trunk/lib/CodeGen/CodeGenFunction.cpp Thu Jan 26 14:40:47 2017 @@ -200,7 +200,8 @@ TypeEvaluationKind CodeGenFunction::getE llvm_unreachable("non-canonical or dependent type in IR-generation"); case Type::Auto: - llvm_unreachable("undeduced auto type in IR-generation"); + case Type::DeducedTemplateSpecialization: + llvm_unreachable("undeduced type in IR-generation"); // Various scalar types. case Type::Builtin: @@ -1899,6 +1900,7 @@ void CodeGenFunction::EmitVariablyModifi case Type::Typedef: case Type::Decltype: case Type::Auto: + case Type::DeducedTemplateSpecialization: // Stop walking: nothing to do. return; Modified: cfe/trunk/lib/CodeGen/CodeGenTypes.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenTypes.cpp?rev=293207&r1=293206&r2=293207&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CodeGenTypes.cpp (original) +++ cfe/trunk/lib/CodeGen/CodeGenTypes.cpp Thu Jan 26 14:40:47 2017 @@ -487,7 +487,8 @@ llvm::Type *CodeGenTypes::ConvertType(Qu break; } case Type::Auto: - llvm_unreachable("Unexpected undeduced auto type!"); + case Type::DeducedTemplateSpecialization: + llvm_unreachable("Unexpected undeduced type!"); case Type::Complex: { llvm::Type *EltTy = ConvertType(cast<ComplexType>(Ty)->getElementType()); ResultType = llvm::StructType::get(EltTy, EltTy, nullptr); Modified: cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp?rev=293207&r1=293206&r2=293207&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp (original) +++ cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp Thu Jan 26 14:40:47 2017 @@ -2815,7 +2815,8 @@ void ItaniumRTTIBuilder::BuildVTablePoin llvm_unreachable("References shouldn't get here"); case Type::Auto: - llvm_unreachable("Undeduced auto type shouldn't get here"); + case Type::DeducedTemplateSpecialization: + llvm_unreachable("Undeduced type shouldn't get here"); case Type::Pipe: llvm_unreachable("Pipe types shouldn't get here"); @@ -3045,7 +3046,8 @@ llvm::Constant *ItaniumRTTIBuilder::Buil llvm_unreachable("References shouldn't get here"); case Type::Auto: - llvm_unreachable("Undeduced auto type shouldn't get here"); + case Type::DeducedTemplateSpecialization: + llvm_unreachable("Undeduced type shouldn't get here"); case Type::Pipe: llvm_unreachable("Pipe type shouldn't get here"); Modified: cfe/trunk/lib/Parse/ParseDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=293207&r1=293206&r2=293207&view=diff ============================================================================== --- cfe/trunk/lib/Parse/ParseDecl.cpp (original) +++ cfe/trunk/lib/Parse/ParseDecl.cpp Thu Jan 26 14:40:47 2017 @@ -2884,7 +2884,8 @@ void Parser::ParseDeclarationSpecifiers( Actions.getTypeName(*Next.getIdentifierInfo(), Next.getLocation(), getCurScope(), &SS, false, false, nullptr, /*IsCtorOrDtorName=*/false, - /*NonTrivialSourceInfo=*/true); + /*WantNonTrivialSourceInfo=*/true, + isClassTemplateDeductionContext(DSContext)); // If the referenced identifier is not a type, then this declspec is // erroneous: We already checked about that it has no type specifier, and @@ -2998,9 +2999,10 @@ void Parser::ParseDeclarationSpecifiers( continue; } - ParsedType TypeRep = - Actions.getTypeName(*Tok.getIdentifierInfo(), - Tok.getLocation(), getCurScope()); + ParsedType TypeRep = Actions.getTypeName( + *Tok.getIdentifierInfo(), Tok.getLocation(), getCurScope(), nullptr, + false, false, nullptr, false, false, + isClassTemplateDeductionContext(DSContext)); // If this is not a typedef name, don't parse it as part of the declspec, // it must be an implicit int or an error. Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=293207&r1=293206&r2=293207&view=diff ============================================================================== --- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original) +++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Thu Jan 26 14:40:47 2017 @@ -1144,10 +1144,11 @@ TypeResult Parser::ParseBaseTypeSpecifie // We have an identifier; check whether it is actually a type. IdentifierInfo *CorrectedII = nullptr; - ParsedType Type = - Actions.getTypeName(*Id, IdLoc, getCurScope(), &SS, true, false, nullptr, - /*IsCtorOrDtorName=*/false, - /*NonTrivialTypeSourceInfo=*/true, &CorrectedII); + ParsedType Type = Actions.getTypeName( + *Id, IdLoc, getCurScope(), &SS, true, false, nullptr, + /*IsCtorOrDtorName=*/false, + /*NonTrivialTypeSourceInfo=*/true, + /*IsClassTemplateDeductionContext*/ false, &CorrectedII); if (!Type) { Diag(IdLoc, diag::err_expected_class_name); return true; Modified: cfe/trunk/lib/Parse/ParseExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=293207&r1=293206&r2=293207&view=diff ============================================================================== --- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original) +++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Thu Jan 26 14:40:47 2017 @@ -1639,9 +1639,10 @@ ExprResult Parser::ParseCXXThis() { /// typename-specifier '(' expression-list[opt] ')' /// [C++0x] typename-specifier braced-init-list /// +/// In C++1z onwards, the type specifier can also be a template-name. ExprResult Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) { - Declarator DeclaratorInfo(DS, Declarator::TypeNameContext); + Declarator DeclaratorInfo(DS, Declarator::FunctionalCastContext); ParsedType TypeRep = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo).get(); assert((Tok.is(tok::l_paren) || Modified: cfe/trunk/lib/Parse/Parser.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/Parser.cpp?rev=293207&r1=293206&r2=293207&view=diff ============================================================================== --- cfe/trunk/lib/Parse/Parser.cpp (original) +++ cfe/trunk/lib/Parse/Parser.cpp Thu Jan 26 14:40:47 2017 @@ -1743,7 +1743,8 @@ bool Parser::TryAnnotateTypeOrScopeToken *Tok.getIdentifierInfo(), Tok.getLocation(), getCurScope(), &SS, false, NextToken().is(tok::period), nullptr, /*IsCtorOrDtorName=*/false, - /*NonTrivialTypeSourceInfo*/ true)) { + /*NonTrivialTypeSourceInfo*/ true, + /*IsClassTemplateDeductionContext*/GreaterThanIsOperator)) { SourceLocation BeginLoc = Tok.getLocation(); if (SS.isNotEmpty()) // it was a C++ qualified type name. BeginLoc = SS.getBeginLoc(); Modified: cfe/trunk/lib/Sema/SemaDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=293207&r1=293206&r2=293207&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDecl.cpp (original) +++ cfe/trunk/lib/Sema/SemaDecl.cpp Thu Jan 26 14:40:47 2017 @@ -60,6 +60,11 @@ Sema::DeclGroupPtrTy Sema::ConvertDeclTo return DeclGroupPtrTy::make(DeclGroupRef(Ptr)); } +static bool isTypeTemplate(NamedDecl *ND) { + return isa<ClassTemplateDecl>(ND) || isa<TypeAliasTemplateDecl>(ND) || + isa<TemplateTemplateParmDecl>(ND); +} + namespace { class TypeNameValidatorCCC : public CorrectionCandidateCallback { @@ -67,7 +72,7 @@ class TypeNameValidatorCCC : public Corr TypeNameValidatorCCC(bool AllowInvalid, bool WantClass=false, bool AllowTemplates=false) : AllowInvalidDecl(AllowInvalid), WantClassName(WantClass), - AllowClassTemplates(AllowTemplates) { + AllowTemplates(AllowTemplates) { WantExpressionKeywords = false; WantCXXNamedCasts = false; WantRemainingKeywords = false; @@ -76,7 +81,7 @@ class TypeNameValidatorCCC : public Corr bool ValidateCandidate(const TypoCorrection &candidate) override { if (NamedDecl *ND = candidate.getCorrectionDecl()) { bool IsType = isa<TypeDecl>(ND) || isa<ObjCInterfaceDecl>(ND); - bool AllowedTemplate = AllowClassTemplates && isa<ClassTemplateDecl>(ND); + bool AllowedTemplate = AllowTemplates && isTypeTemplate(ND); return (IsType || AllowedTemplate) && (AllowInvalidDecl || !ND->isInvalidDecl()); } @@ -86,7 +91,7 @@ class TypeNameValidatorCCC : public Corr private: bool AllowInvalidDecl; bool WantClassName; - bool AllowClassTemplates; + bool AllowTemplates; }; } // end anonymous namespace @@ -252,7 +257,13 @@ ParsedType Sema::getTypeName(const Ident ParsedType ObjectTypePtr, bool IsCtorOrDtorName, bool WantNontrivialTypeSourceInfo, + bool IsClassTemplateDeductionContext, IdentifierInfo **CorrectedII) { + // FIXME: Consider allowing this outside C++1z mode as an extension. + bool AllowDeducedTemplate = IsClassTemplateDeductionContext && + getLangOpts().CPlusPlus1z && !IsCtorOrDtorName && + !isClassName && !HasTrailingDot; + // Determine where we will perform name lookup. DeclContext *LookupCtx = nullptr; if (ObjectTypePtr) { @@ -334,10 +345,11 @@ ParsedType Sema::getTypeName(const Ident case LookupResult::NotFound: case LookupResult::NotFoundInCurrentInstantiation: if (CorrectedII) { - TypoCorrection Correction = CorrectTypo( - Result.getLookupNameInfo(), Kind, S, SS, - llvm::make_unique<TypeNameValidatorCCC>(true, isClassName), - CTK_ErrorRecovery); + TypoCorrection Correction = + CorrectTypo(Result.getLookupNameInfo(), Kind, S, SS, + llvm::make_unique<TypeNameValidatorCCC>( + true, isClassName, AllowDeducedTemplate), + CTK_ErrorRecovery); IdentifierInfo *NewII = Correction.getCorrectionAsIdentifierInfo(); TemplateTy Template; bool MemberOfUnknownSpecialization; @@ -359,7 +371,8 @@ ParsedType Sema::getTypeName(const Ident ParsedType Ty = getTypeName(*NewII, NameLoc, S, NewSSPtr, isClassName, HasTrailingDot, ObjectTypePtr, IsCtorOrDtorName, - WantNontrivialTypeSourceInfo); + WantNontrivialTypeSourceInfo, + IsClassTemplateDeductionContext); if (Ty) { diagnoseTypo(Correction, PDiag(diag::err_unknown_type_or_class_name_suggest) @@ -391,7 +404,8 @@ ParsedType Sema::getTypeName(const Ident // Look to see if we have a type anywhere in the list of results. for (LookupResult::iterator Res = Result.begin(), ResEnd = Result.end(); Res != ResEnd; ++Res) { - if (isa<TypeDecl>(*Res) || isa<ObjCInterfaceDecl>(*Res)) { + if (isa<TypeDecl>(*Res) || isa<ObjCInterfaceDecl>(*Res) || + (AllowDeducedTemplate && isTypeTemplate(*Res))) { if (!IIDecl || (*Res)->getLocation().getRawEncoding() < IIDecl->getLocation().getRawEncoding()) @@ -440,29 +454,13 @@ ParsedType Sema::getTypeName(const Ident T = Context.getTypeDeclType(TD); MarkAnyDeclReferenced(TD->getLocation(), TD, /*OdrUse=*/false); - - // NOTE: avoid constructing an ElaboratedType(Loc) if this is a - // constructor or destructor name (in such a case, the scope specifier - // will be attached to the enclosing Expr or Decl node). - if (SS && SS->isNotEmpty() && !IsCtorOrDtorName) { - if (WantNontrivialTypeSourceInfo) { - // Construct a type with type-source information. - TypeLocBuilder Builder; - Builder.pushTypeSpec(T).setNameLoc(NameLoc); - - T = getElaboratedType(ETK_None, *SS, T); - ElaboratedTypeLoc ElabTL = Builder.push<ElaboratedTypeLoc>(T); - ElabTL.setElaboratedKeywordLoc(SourceLocation()); - ElabTL.setQualifierLoc(SS->getWithLocInContext(Context)); - return CreateParsedType(T, Builder.getTypeSourceInfo(Context, T)); - } else { - T = getElaboratedType(ETK_None, *SS, T); - } - } } else if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(IIDecl)) { (void)DiagnoseUseOfDecl(IDecl, NameLoc); if (!HasTrailingDot) T = Context.getObjCInterfaceType(IDecl); + } else if (AllowDeducedTemplate && isTypeTemplate(IIDecl)) { + T = Context.getDeducedTemplateSpecializationType( + TemplateName(cast<TemplateDecl>(IIDecl)), QualType(), false); } if (T.isNull()) { @@ -470,6 +468,27 @@ ParsedType Sema::getTypeName(const Ident Result.suppressDiagnostics(); return nullptr; } + + // NOTE: avoid constructing an ElaboratedType(Loc) if this is a + // constructor or destructor name (in such a case, the scope specifier + // will be attached to the enclosing Expr or Decl node). + if (SS && SS->isNotEmpty() && !IsCtorOrDtorName && + !isa<ObjCInterfaceDecl>(IIDecl)) { + if (WantNontrivialTypeSourceInfo) { + // Construct a type with type-source information. + TypeLocBuilder Builder; + Builder.pushTypeSpec(T).setNameLoc(NameLoc); + + T = getElaboratedType(ETK_None, *SS, T); + ElaboratedTypeLoc ElabTL = Builder.push<ElaboratedTypeLoc>(T); + ElabTL.setElaboratedKeywordLoc(SourceLocation()); + ElabTL.setQualifierLoc(SS->getWithLocInContext(Context)); + return CreateParsedType(T, Builder.getTypeSourceInfo(Context, T)); + } else { + T = getElaboratedType(ETK_None, *SS, T); + } + } + return ParsedType::make(T); } @@ -647,6 +666,7 @@ void Sema::DiagnoseUnknownTypeName(Ident if (Corrected.getCorrectionSpecifier()) tmpSS.MakeTrivial(Context, Corrected.getCorrectionSpecifier(), SourceRange(IILoc)); + // FIXME: Support class template argument deduction here. SuggestedType = getTypeName(*Corrected.getCorrectionAsIdentifierInfo(), IILoc, S, tmpSS.isSet() ? &tmpSS : SS, false, false, nullptr, @@ -9740,6 +9760,14 @@ QualType Sema::deduceVarTypeFromInitiali VarDeclOrName VN{VDecl, Name}; + DeducedType *Deduced = Type->getContainedDeducedType(); + assert(Deduced && "deduceVarTypeFromInitializer for non-deduced type"); + + if (isa<DeducedTemplateSpecializationType>(Deduced)) { + Diag(Init->getLocStart(), diag::err_deduced_class_template_not_supported); + return QualType(); + } + ArrayRef<Expr *> DeduceInits = Init; if (DirectInit) { if (auto *PL = dyn_cast<ParenListExpr>(Init)) Modified: cfe/trunk/lib/Sema/SemaExpr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=293207&r1=293206&r2=293207&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExpr.cpp (original) +++ cfe/trunk/lib/Sema/SemaExpr.cpp Thu Jan 26 14:40:47 2017 @@ -3976,7 +3976,8 @@ static void captureVariablyModifiedType( T = cast<DecltypeType>(Ty)->desugar(); break; case Type::Auto: - T = cast<AutoType>(Ty)->getDeducedType(); + case Type::DeducedTemplateSpecialization: + T = cast<DeducedType>(Ty)->getDeducedType(); break; case Type::TypeOfExpr: T = cast<TypeOfExprType>(Ty)->getUnderlyingExpr()->getType(); Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=293207&r1=293206&r2=293207&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original) +++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Thu Jan 26 14:40:47 2017 @@ -1255,9 +1255,19 @@ Sema::BuildCXXTypeConstructExpr(TypeSour RParenLoc); } + // C++1z [expr.type.conv]p1: + // If the type is a placeholder for a deduced class type, [...perform class + // template argument deduction...] + DeducedType *Deduced = Ty->getContainedDeducedType(); + if (Deduced && isa<DeducedTemplateSpecializationType>(Deduced)) { + Diag(TyBeginLoc, diag::err_deduced_class_template_not_supported); + return ExprError(); + } + bool ListInitialization = LParenLoc.isInvalid(); - assert((!ListInitialization || (Exprs.size() == 1 && isa<InitListExpr>(Exprs[0]))) - && "List initialization must have initializer list as expression."); + assert((!ListInitialization || + (Exprs.size() == 1 && isa<InitListExpr>(Exprs[0]))) && + "List initialization must have initializer list as expression."); SourceRange FullRange = SourceRange(TyBeginLoc, ListInitialization ? Exprs[0]->getSourceRange().getEnd() : RParenLoc); @@ -1646,6 +1656,11 @@ Sema::BuildCXXNew(SourceRange Range, boo // C++11 [dcl.spec.auto]p6. Deduce the type which 'auto' stands in for. if (AllocType->isUndeducedType()) { + if (isa<DeducedTemplateSpecializationType>( + AllocType->getContainedDeducedType())) + return ExprError(Diag(TypeRange.getBegin(), + diag::err_deduced_class_template_not_supported)); + if (initStyle == CXXNewExpr::NoInit || NumInits == 0) return ExprError(Diag(StartLoc, diag::err_auto_new_requires_ctor_arg) << AllocType << TypeRange); Modified: cfe/trunk/lib/Sema/SemaLookup.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLookup.cpp?rev=293207&r1=293206&r2=293207&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaLookup.cpp (original) +++ cfe/trunk/lib/Sema/SemaLookup.cpp Thu Jan 26 14:40:47 2017 @@ -2694,6 +2694,7 @@ addAssociatedClassesAndNamespaces(Associ // Non-deduced auto types only get here for error cases. case Type::Auto: + case Type::DeducedTemplateSpecialization: break; // If T is an Objective-C object or interface type, or a pointer to an Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=293207&r1=293206&r2=293207&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplate.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplate.cpp Thu Jan 26 14:40:47 2017 @@ -4439,6 +4439,11 @@ bool UnnamedLocalNoLinkageFinder::VisitA return Visit(T->getDeducedType()); } +bool UnnamedLocalNoLinkageFinder::VisitDeducedTemplateSpecializationType( + const DeducedTemplateSpecializationType *T) { + return Visit(T->getDeducedType()); +} + bool UnnamedLocalNoLinkageFinder::VisitRecordType(const RecordType* T) { return VisitTagDecl(T->getDecl()); } @@ -8786,6 +8791,9 @@ Sema::CheckTypenameType(ElaboratedTypeKe Context.getTypeDeclType(Type)); } + // FIXME: Form a deduced template specialization type if we get a template + // declaration here. + DiagID = diag::err_typename_nested_not_type; Referenced = Result.getFoundDecl(); break; Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=293207&r1=293206&r2=293207&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Thu Jan 26 14:40:47 2017 @@ -1723,6 +1723,7 @@ DeduceTemplateArgumentsByTypeMatch(Sema case Type::Decltype: case Type::UnaryTransform: case Type::Auto: + case Type::DeducedTemplateSpecialization: case Type::DependentTemplateSpecialization: case Type::PackExpansion: case Type::Pipe: @@ -5152,8 +5153,9 @@ MarkUsedTemplateParameters(ASTContext &C break; case Type::Auto: + case Type::DeducedTemplateSpecialization: MarkUsedTemplateParameters(Ctx, - cast<AutoType>(T)->getDeducedType(), + cast<DeducedType>(T)->getDeducedType(), OnlyDeduced, Depth, Used); // None of these types have any template parameters in them. Modified: cfe/trunk/lib/Sema/SemaType.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=293207&r1=293206&r2=293207&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaType.cpp (original) +++ cfe/trunk/lib/Sema/SemaType.cpp Thu Jan 26 14:40:47 2017 @@ -2778,12 +2778,20 @@ static QualType GetDeclSpecTypeForDeclar distributeTypeAttrsFromDeclarator(state, T); // C++11 [dcl.spec.auto]p5: reject 'auto' if it is not in an allowed context. - if (D.getDeclSpec().containsPlaceholderType()) { + if (DeducedType *Deduced = T->getContainedDeducedType()) { + AutoType *Auto = dyn_cast<AutoType>(Deduced); int Error = -1; + // Is this a 'auto' or 'decltype(auto)' type (as opposed to __auto_type or + // class template argument deduction)? + bool IsCXXAutoType = + (Auto && Auto->getKeyword() != AutoTypeKeyword::GNUAutoType); + switch (D.getContext()) { case Declarator::LambdaExprContext: - llvm_unreachable("Can't specify a type specifier in lambda grammar"); + // Declared return type of a lambda-declarator is implicit and is always + // 'auto'. + break; case Declarator::ObjCParameterContext: case Declarator::ObjCResultContext: case Declarator::PrototypeContext: @@ -2791,8 +2799,8 @@ static QualType GetDeclSpecTypeForDeclar break; case Declarator::LambdaExprParameterContext: // In C++14, generic lambdas allow 'auto' in their parameters. - if (!(SemaRef.getLangOpts().CPlusPlus14 - && D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto)) + if (!SemaRef.getLangOpts().CPlusPlus14 || + !Auto || Auto->getKeyword() != AutoTypeKeyword::Auto) Error = 16; break; case Declarator::MemberContext: { @@ -2807,6 +2815,8 @@ static QualType GetDeclSpecTypeForDeclar case TTK_Class: Error = 5; /* Class member */ break; case TTK_Interface: Error = 6; /* Interface member */ break; } + if (D.getDeclSpec().isFriendSpecified()) + Error = 20; // Friend type break; } case Declarator::CXXCatchContext: @@ -2814,8 +2824,10 @@ static QualType GetDeclSpecTypeForDeclar Error = 7; // Exception declaration break; case Declarator::TemplateParamContext: - if (!SemaRef.getLangOpts().CPlusPlus1z) - Error = 8; // Template parameter + if (isa<DeducedTemplateSpecializationType>(Deduced)) + Error = 19; // Template parameter + else if (!SemaRef.getLangOpts().CPlusPlus1z) + Error = 8; // Template parameter (until C++1z) break; case Declarator::BlockLiteralContext: Error = 9; // Block literal @@ -2828,15 +2840,17 @@ static QualType GetDeclSpecTypeForDeclar Error = 12; // Type alias break; case Declarator::TrailingReturnContext: - if (!SemaRef.getLangOpts().CPlusPlus14 || - D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto_type) + if (!SemaRef.getLangOpts().CPlusPlus14 || !IsCXXAutoType) Error = 13; // Function return type break; case Declarator::ConversionIdContext: - if (!SemaRef.getLangOpts().CPlusPlus14 || - D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto_type) + if (!SemaRef.getLangOpts().CPlusPlus14 || !IsCXXAutoType) Error = 14; // conversion-type-id break; + case Declarator::FunctionalCastContext: + if (isa<DeducedTemplateSpecializationType>(Deduced)) + break; + LLVM_FALLTHROUGH; case Declarator::TypeNameContext: Error = 15; // Generic break; @@ -2845,9 +2859,14 @@ static QualType GetDeclSpecTypeForDeclar case Declarator::ForContext: case Declarator::InitStmtContext: case Declarator::ConditionContext: + // FIXME: P0091R3 (erroneously) does not permit class template argument + // deduction in conditions, for-init-statements, and other declarations + // that are not simple-declarations. break; case Declarator::CXXNewContext: - if (D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto_type) + // FIXME: P0091R3 does not permit class template argument deduction here, + // but we follow GCC and allow it anyway. + if (!IsCXXAutoType && !isa<DeducedTemplateSpecializationType>(Deduced)) Error = 17; // 'new' type break; case Declarator::KNRTypeListContext: @@ -2861,8 +2880,7 @@ static QualType GetDeclSpecTypeForDeclar // In Objective-C it is an error to use 'auto' on a function declarator // (and everywhere for '__auto_type'). if (D.isFunctionDeclarator() && - (!SemaRef.getLangOpts().CPlusPlus11 || - D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto_type)) + (!SemaRef.getLangOpts().CPlusPlus11 || !IsCXXAutoType)) Error = 13; bool HaveTrailing = false; @@ -2872,8 +2890,8 @@ static QualType GetDeclSpecTypeForDeclar // level. Check all declarator chunks (outermost first) anyway, to give // better diagnostics. // We don't support '__auto_type' with trailing return types. - if (SemaRef.getLangOpts().CPlusPlus11 && - D.getDeclSpec().getTypeSpecType() != DeclSpec::TST_auto_type) { + // FIXME: Should we only do this for 'auto' and not 'decltype(auto)'? + if (SemaRef.getLangOpts().CPlusPlus11 && IsCXXAutoType) { for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) { unsigned chunkIndex = e - i - 1; state.setCurrentChunkIndex(chunkIndex); @@ -2894,15 +2912,28 @@ static QualType GetDeclSpecTypeForDeclar AutoRange = D.getName().getSourceRange(); if (Error != -1) { - unsigned Keyword; - switch (D.getDeclSpec().getTypeSpecType()) { - case DeclSpec::TST_auto: Keyword = 0; break; - case DeclSpec::TST_decltype_auto: Keyword = 1; break; - case DeclSpec::TST_auto_type: Keyword = 2; break; - default: llvm_unreachable("unknown auto TypeSpecType"); + unsigned Kind; + if (Auto) { + switch (Auto->getKeyword()) { + case AutoTypeKeyword::Auto: Kind = 0; break; + case AutoTypeKeyword::DecltypeAuto: Kind = 1; break; + case AutoTypeKeyword::GNUAutoType: Kind = 2; break; + } + } else { + assert(isa<DeducedTemplateSpecializationType>(Deduced) && + "unknown auto type"); + Kind = 3; } + + auto *DTST = dyn_cast<DeducedTemplateSpecializationType>(Deduced); + TemplateName TN = DTST ? DTST->getTemplateName() : TemplateName(); + SemaRef.Diag(AutoRange.getBegin(), diag::err_auto_not_allowed) - << Keyword << Error << AutoRange; + << Kind << Error << (int)SemaRef.getTemplateNameKindForDiagnostics(TN) + << QualType(Deduced, 0) << AutoRange; + if (auto *TD = TN.getAsTemplateDecl()) + SemaRef.Diag(TD->getLocation(), diag::note_template_decl_here); + T = SemaRef.Context.IntTy; D.setInvalidType(true); } else if (!HaveTrailing) { @@ -2942,6 +2973,7 @@ static QualType GetDeclSpecTypeForDeclar DiagID = diag::err_type_defined_in_alias_template; break; case Declarator::TypeNameContext: + case Declarator::FunctionalCastContext: case Declarator::ConversionIdContext: case Declarator::TemplateParamContext: case Declarator::CXXNewContext: @@ -3623,17 +3655,32 @@ static TypeSourceInfo *GetFullTypeForDec // If T is 'decltype(auto)', the only declarators we can have are parens // and at most one function declarator if this is a function declaration. - if (const AutoType *AT = T->getAs<AutoType>()) { - if (AT->isDecltypeAuto()) { + // If T is a deduced class template specialization type, we can have no + // declarator chunks at all. + if (auto *DT = T->getAs<DeducedType>()) { + const AutoType *AT = T->getAs<AutoType>(); + bool IsClassTemplateDeduction = isa<DeducedTemplateSpecializationType>(DT); + if ((AT && AT->isDecltypeAuto()) || IsClassTemplateDeduction) { for (unsigned I = 0, E = D.getNumTypeObjects(); I != E; ++I) { unsigned Index = E - I - 1; DeclaratorChunk &DeclChunk = D.getTypeObject(Index); - unsigned DiagId = diag::err_decltype_auto_compound_type; + unsigned DiagId = IsClassTemplateDeduction + ? diag::err_deduced_class_template_compound_type + : diag::err_decltype_auto_compound_type; unsigned DiagKind = 0; switch (DeclChunk.Kind) { case DeclaratorChunk::Paren: + // FIXME: Rejecting this is a little silly. + if (IsClassTemplateDeduction) { + DiagKind = 4; + break; + } continue; case DeclaratorChunk::Function: { + if (IsClassTemplateDeduction) { + DiagKind = 3; + break; + } unsigned FnIndex; if (D.isFunctionDeclarationContext() && D.isFunctionDeclarator(FnIndex) && FnIndex == Index) @@ -3834,6 +3881,7 @@ static TypeSourceInfo *GetFullTypeForDec case Declarator::TemplateParamContext: case Declarator::TemplateTypeArgContext: case Declarator::TypeNameContext: + case Declarator::FunctionalCastContext: // Don't infer in these contexts. break; } @@ -4713,6 +4761,7 @@ static TypeSourceInfo *GetFullTypeForDec case Declarator::ObjCParameterContext: // FIXME: special diagnostic here? case Declarator::ObjCResultContext: // FIXME: special diagnostic here? case Declarator::TypeNameContext: + case Declarator::FunctionalCastContext: case Declarator::CXXNewContext: case Declarator::AliasDeclContext: case Declarator::AliasTemplateContext: Modified: cfe/trunk/lib/Sema/TreeTransform.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=293207&r1=293206&r2=293207&view=diff ============================================================================== --- cfe/trunk/lib/Sema/TreeTransform.h (original) +++ cfe/trunk/lib/Sema/TreeTransform.h Thu Jan 26 14:40:47 2017 @@ -876,6 +876,14 @@ public: /*IsDependent*/ false); } + /// By default, builds a new DeducedTemplateSpecializationType with the given + /// deduced type. + QualType RebuildDeducedTemplateSpecializationType(TemplateName Template, + QualType Deduced) { + return SemaRef.Context.getDeducedTemplateSpecializationType( + Template, Deduced, /*IsDependent*/ false); + } + /// \brief Build a new template specialization type. /// /// By default, performs semantic analysis when building the template @@ -5344,6 +5352,37 @@ QualType TreeTransform<Derived>::Transfo return Result; } + +template<typename Derived> +QualType TreeTransform<Derived>::TransformDeducedTemplateSpecializationType( + TypeLocBuilder &TLB, DeducedTemplateSpecializationTypeLoc TL) { + const DeducedTemplateSpecializationType *T = TL.getTypePtr(); + + CXXScopeSpec SS; + TemplateName TemplateName = getDerived().TransformTemplateName( + SS, T->getTemplateName(), TL.getTemplateNameLoc()); + if (TemplateName.isNull()) + return QualType(); + + QualType OldDeduced = T->getDeducedType(); + QualType NewDeduced; + if (!OldDeduced.isNull()) { + NewDeduced = getDerived().TransformType(OldDeduced); + if (NewDeduced.isNull()) + return QualType(); + } + + QualType Result = getDerived().RebuildDeducedTemplateSpecializationType( + TemplateName, NewDeduced); + if (Result.isNull()) + return QualType(); + + DeducedTemplateSpecializationTypeLoc NewTL = + TLB.push<DeducedTemplateSpecializationTypeLoc>(Result); + NewTL.setTemplateNameLoc(TL.getTemplateNameLoc()); + + return Result; +} template<typename Derived> QualType TreeTransform<Derived>::TransformRecordType(TypeLocBuilder &TLB, Modified: cfe/trunk/lib/Serialization/ASTReader.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=293207&r1=293206&r2=293207&view=diff ============================================================================== --- cfe/trunk/lib/Serialization/ASTReader.cpp (original) +++ cfe/trunk/lib/Serialization/ASTReader.cpp Thu Jan 26 14:40:47 2017 @@ -5651,6 +5651,14 @@ QualType ASTReader::readTypeRecord(unsig return Context.getAutoType(Deduced, Keyword, IsDependent); } + case TYPE_DEDUCED_TEMPLATE_SPECIALIZATION: { + TemplateName Name = ReadTemplateName(*Loc.F, Record, Idx); + QualType Deduced = readType(*Loc.F, Record, Idx); + bool IsDependent = Deduced.isNull() ? Record[Idx++] : false; + return Context.getDeducedTemplateSpecializationType(Name, Deduced, + IsDependent); + } + case TYPE_RECORD: { if (Record.size() != 2) { Error("incorrect encoding of record type"); @@ -6082,6 +6090,11 @@ void TypeLocReader::VisitAutoTypeLoc(Aut TL.setNameLoc(ReadSourceLocation()); } +void TypeLocReader::VisitDeducedTemplateSpecializationTypeLoc( + DeducedTemplateSpecializationTypeLoc TL) { + TL.setTemplateNameLoc(ReadSourceLocation()); +} + void TypeLocReader::VisitRecordTypeLoc(RecordTypeLoc TL) { TL.setNameLoc(ReadSourceLocation()); } Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=293207&r1=293206&r2=293207&view=diff ============================================================================== --- cfe/trunk/lib/Serialization/ASTWriter.cpp (original) +++ cfe/trunk/lib/Serialization/ASTWriter.cpp Thu Jan 26 14:40:47 2017 @@ -349,6 +349,15 @@ void ASTTypeWriter::VisitAutoType(const Code = TYPE_AUTO; } +void ASTTypeWriter::VisitDeducedTemplateSpecializationType( + const DeducedTemplateSpecializationType *T) { + Record.AddTemplateName(T->getTemplateName()); + Record.AddTypeRef(T->getDeducedType()); + if (T->getDeducedType().isNull()) + Record.push_back(T->isDependentType()); + Code = TYPE_DEDUCED_TEMPLATE_SPECIALIZATION; +} + void ASTTypeWriter::VisitTagType(const TagType *T) { Record.push_back(T->isDependentType()); Record.AddDeclRef(T->getDecl()->getCanonicalDecl()); @@ -683,6 +692,11 @@ void TypeLocWriter::VisitAutoTypeLoc(Aut Record.AddSourceLocation(TL.getNameLoc()); } +void TypeLocWriter::VisitDeducedTemplateSpecializationTypeLoc( + DeducedTemplateSpecializationTypeLoc TL) { + Record.AddSourceLocation(TL.getTemplateNameLoc()); +} + void TypeLocWriter::VisitRecordTypeLoc(RecordTypeLoc TL) { Record.AddSourceLocation(TL.getNameLoc()); } Modified: cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp?rev=293207&r1=293206&r2=293207&view=diff ============================================================================== --- cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp (original) +++ cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp Thu Jan 26 14:40:47 2017 @@ -9,7 +9,7 @@ struct S { void f() throw (auto); // expected-error{{'auto' not allowed here}} - friend auto; // expected-error{{'auto' not allowed in non-static struct member}} + friend auto; // expected-error{{'auto' not allowed in friend declaration}} operator auto(); // expected-error{{'auto' not allowed in conversion function type}} }; Modified: cfe/trunk/test/CXX/drs/dr5xx.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr5xx.cpp?rev=293207&r1=293206&r2=293207&view=diff ============================================================================== --- cfe/trunk/test/CXX/drs/dr5xx.cpp (original) +++ cfe/trunk/test/CXX/drs/dr5xx.cpp Thu Jan 26 14:40:47 2017 @@ -877,13 +877,25 @@ namespace dr583 { // dr583: 4 namespace dr585 { // dr585: yes template<typename> struct T; struct A { - friend T; // expected-error {{requires a type specifier}} expected-error {{can only be classes or functions}} + friend T; +#if __cplusplus <= 201402L + // expected-error@-2 {{requires a type specifier}} expected-error@-2 {{can only be classes or functions}} +#else + // expected-error@-4 {{use of class template 'T' requires template arguments; argument deduction not allowed in friend declaration}} + // expected-note@-7 {{here}} +#endif // FIXME: It's not clear whether the standard allows this or what it means, // but the DR585 writeup suggests it as an alternative. template<typename U> friend T<U>; // expected-error {{must use an elaborated type}} }; template<template<typename> class T> struct B { - friend T; // expected-error {{requires a type specifier}} expected-error {{can only be classes or functions}} + friend T; +#if __cplusplus <= 201402L + // expected-error@-2 {{requires a type specifier}} expected-error@-2 {{can only be classes or functions}} +#else + // expected-error@-4 {{use of template template parameter 'T' requires template arguments; argument deduction not allowed in friend declaration}} + // expected-note@-6 {{here}} +#endif template<typename U> friend T<U>; // expected-error {{must use an elaborated type}} }; } Modified: cfe/trunk/test/Parser/backtrack-off-by-one.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/backtrack-off-by-one.cpp?rev=293207&r1=293206&r2=293207&view=diff ============================================================================== --- cfe/trunk/test/Parser/backtrack-off-by-one.cpp (original) +++ cfe/trunk/test/Parser/backtrack-off-by-one.cpp Thu Jan 26 14:40:47 2017 @@ -1,6 +1,7 @@ // RUN: %clang_cc1 -verify %s // RUN: %clang_cc1 -verify %s -std=c++98 // RUN: %clang_cc1 -verify %s -std=c++11 +// RUN: %clang_cc1 -verify %s -std=c++1z // PR25946 // We had an off-by-one error in an assertion when annotating A<int> below. Our @@ -13,9 +14,13 @@ template <typename T> class A {}; // expected-error@+1 {{expected '{' after base class list}} template <typename T> class B : T // not ',' or '{' #if __cplusplus < 201103L -// expected-error@+4 {{expected ';' after top level declarator}} +// expected-error@+8 {{expected ';' after top level declarator}} +#endif +#if __cplusplus <= 201402L +// expected-error@+5 {{C++ requires a type specifier for all declarations}} +#else +// expected-error@+3 {{expected unqualified-id}} #endif -// expected-error@+2 {{C++ requires a type specifier for all declarations}} // expected-error@+1 {{expected ';' after class}} A<int> { }; Added: cfe/trunk/test/Parser/cxx1z-class-template-argument-deduction.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx1z-class-template-argument-deduction.cpp?rev=293207&view=auto ============================================================================== --- cfe/trunk/test/Parser/cxx1z-class-template-argument-deduction.cpp (added) +++ cfe/trunk/test/Parser/cxx1z-class-template-argument-deduction.cpp Thu Jan 26 14:40:47 2017 @@ -0,0 +1,131 @@ +// RUN: %clang_cc1 -std=c++1z -fcxx-exceptions -verify %s + +template<typename T> struct A {}; // expected-note 31{{declared here}} + +// Make sure we still correctly parse cases where a template can appear without arguments. +namespace template_template_arg { + template<template<typename> typename> struct X {}; + template<typename> struct Y {}; + + X<A> xa; + Y<A> ya; // expected-error {{requires template arguments}} + X<::A> xcca; + Y<::A> ycca; // expected-error {{requires template arguments}} + + template<template<typename> typename = A> struct XD {}; + template<typename = A> struct YD {}; // expected-error {{requires template arguments}} + template<template<typename> typename = ::A> struct XCCD {}; + template<typename = ::A> struct YCCD {}; // expected-error {{requires template arguments}} + + // FIXME: replacing the invalid type with 'int' here is horrible + template <A a = A<int>()> class C { }; // expected-error {{requires template arguments}} expected-error {{not implicitly convertible to 'int'}} + template<typename T = A> struct G { }; // expected-error {{requires template arguments}} +} + +namespace injected_class_name { + template<typename T> struct A { + A(T); + void f(int) { + A a = 1; + injected_class_name::A b = 1; // expected-error {{not yet supported}} + } + void f(T); + }; + A<short> ai = 1; + A<double>::A b(1); // expected-error {{constructor name}} +} + +struct member { + A a; // expected-error {{requires template arguments}} + A *b; // expected-error {{requires template arguments}} + const A c; // expected-error {{requires template arguments}} + + void f() throw (A); // expected-error {{requires template arguments}} + + friend A; // expected-error {{requires template arguments; argument deduction not allowed in friend declaration}} + + operator A(); // expected-error {{requires template arguments; argument deduction not allowed in conversion function type}} + + static A x; // expected-error {{requires an initializer}} + static A y = 0; // expected-error {{not yet supported}} +}; + +namespace in_typedef { + typedef A *AutoPtr; // expected-error {{requires template arguments; argument deduction not allowed in typedef}} + typedef A (*PFun)(int a); // expected-error{{requires template arguments; argument deduction not allowed in typedef}} + typedef A Fun(int a) -> decltype(a + a); // expected-error{{requires template arguments; argument deduction not allowed in function return type}} +} + +namespace stmt { + void g(A a) { // expected-error{{requires template arguments; argument deduction not allowed in function prototype}} + try { } + catch (A &a) { } // expected-error{{requires template arguments; argument deduction not allowed in exception declaration}} + catch (const A a) { } // expected-error{{requires template arguments; argument deduction not allowed in exception declaration}} + try { } catch (A a) { } // expected-error{{requires template arguments; argument deduction not allowed in exception declaration}} + + // FIXME: The standard only permits class template argument deduction in a + // simple-declaration or cast. We also permit it in conditions, + // for-range-declarations, member-declarations for static data members, and + // new-expressions, because not doing so would be bizarre. + A local = 0; // expected-error {{not yet supported}} + static A local_static = 0; // expected-error {{not yet supported}} + static thread_local A thread_local_static = 0; // expected-error {{not yet supported}} + if (A a = 0) {} // expected-error {{not yet supported}} + if (A a = 0; a) {} // expected-error {{not yet supported}} + switch (A a = 0) {} // expected-error {{not yet supported}} + switch (A a = 0; a) {} // expected-error {{not yet supported}} + for (A a = 0; a; /**/) {} // expected-error {{not yet supported}} + for (/**/; A a = 0; /**/) {} // expected-error {{not yet supported}} + while (A a = 0) {} // expected-error {{not yet supported}} + int arr[3]; + for (A a : arr) {} // expected-error {{not yet supported}} + } + + namespace std { + class type_info; + } +} + +namespace expr { + template<typename T> struct U {}; + void j() { + (void)typeid(A); // expected-error{{requires template arguments; argument deduction not allowed here}} + (void)sizeof(A); // expected-error{{requires template arguments; argument deduction not allowed here}} + (void)__alignof(A); // expected-error{{requires template arguments; argument deduction not allowed here}} + + U<A> v; // expected-error {{requires template arguments}} + + int n; + (void)dynamic_cast<A&>(n); // expected-error{{requires template arguments; argument deduction not allowed here}} + (void)static_cast<A*>(&n); // expected-error{{requires template arguments; argument deduction not allowed here}} + (void)reinterpret_cast<A*>(&n); // expected-error{{requires template arguments; argument deduction not allowed here}} + (void)const_cast<A>(n); // expected-error{{requires template arguments; argument deduction not allowed here}} + (void)*(A*)(&n); // expected-error{{requires template arguments; argument deduction not allowed here}} + + (void)A(n); // expected-error {{not yet supported}} + (void)A{n}; // expected-error {{not yet supported}} + (void)new A(n); // expected-error {{not yet supported}} + (void)new A{n}; // expected-error {{not yet supported}} + // FIXME: We should diagnose the lack of an initializer here. + (void)new A; // expected-error {{not yet supported}} + } +} + +namespace decl { + enum E : A {}; // expected-error{{requires template arguments; argument deduction not allowed here}} + struct F : A {}; // expected-error{{expected class name}} + + using B = A; // expected-error{{requires template arguments}} + + auto k() -> A; // expected-error{{requires template arguments}} + + A a; // expected-error {{requires an initializer}} + A b = 0; // expected-error {{not yet supported}} + A (parens) = 0; // expected-error {{cannot use parentheses when declaring variable with deduced class template specialization type}} + A *p = 0; // expected-error {{cannot form pointer to deduced class template specialization type}} + A &r = *p; // expected-error {{cannot form reference to deduced class template specialization type}} + A arr[3] = 0; // expected-error {{cannot form array of deduced class template specialization type}} + A F::*pm = 0; // expected-error {{cannot form pointer to deduced class template specialization type}} + A (*fp)() = 0; // expected-error {{cannot form function returning deduced class template specialization type}} + A [x, y] = 0; // expected-error {{cannot be declared with type 'A'}} expected-error {{not yet supported}} +} Modified: cfe/trunk/test/SemaTemplate/temp_arg.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/temp_arg.cpp?rev=293207&r1=293206&r2=293207&view=diff ============================================================================== --- cfe/trunk/test/SemaTemplate/temp_arg.cpp (original) +++ cfe/trunk/test/SemaTemplate/temp_arg.cpp Thu Jan 26 14:40:47 2017 @@ -10,7 +10,7 @@ A<int, 0, X> * a1; A<float, 1, X, double> *a2; // expected-error{{too many template arguments for class template 'A'}} A<float, 1> *a3; // expected-error{{too few template arguments for class template 'A'}} -A a3; // expected-error{{use of class template 'A' requires template arguments}} +A a4; // expected-error{{use of class template 'A' requires template arguments}} namespace test0 { template <class t> class foo {}; Modified: cfe/trunk/test/SemaTemplate/typename-specifier-3.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/typename-specifier-3.cpp?rev=293207&r1=293206&r2=293207&view=diff ============================================================================== --- cfe/trunk/test/SemaTemplate/typename-specifier-3.cpp (original) +++ cfe/trunk/test/SemaTemplate/typename-specifier-3.cpp Thu Jan 26 14:40:47 2017 @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s // PR4364 -template<class T> struct a { +template<class T> struct a { // expected-note {{here}} T b() { return typename T::x(); } @@ -17,3 +17,4 @@ B c() { // Some extra tests for invalid cases template<class T> struct test2 { T b() { return typename T::a; } }; // expected-error{{expected '(' for function-style cast or type construction}} template<class T> struct test3 { T b() { return typename a; } }; // expected-error{{expected a qualified name after 'typename'}} +template<class T> struct test4 { T b() { return typename ::a; } }; // expected-error{{refers to non-type member}} expected-error{{expected '(' for function-style cast or type construction}} Modified: cfe/trunk/tools/libclang/CIndex.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CIndex.cpp?rev=293207&r1=293206&r2=293207&view=diff ============================================================================== --- cfe/trunk/tools/libclang/CIndex.cpp (original) +++ cfe/trunk/tools/libclang/CIndex.cpp Thu Jan 26 14:40:47 2017 @@ -1640,6 +1640,15 @@ bool CursorVisitor::VisitAdjustedTypeLoc return Visit(TL.getOriginalLoc()); } +bool CursorVisitor::VisitDeducedTemplateSpecializationTypeLoc( + DeducedTemplateSpecializationTypeLoc TL) { + if (VisitTemplateName(TL.getTypePtr()->getTemplateName(), + TL.getTemplateNameLoc())) + return true; + + return false; +} + bool CursorVisitor::VisitTemplateSpecializationTypeLoc( TemplateSpecializationTypeLoc TL) { // Visit the template name. Modified: cfe/trunk/tools/libclang/CXType.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CXType.cpp?rev=293207&r1=293206&r2=293207&view=diff ============================================================================== --- cfe/trunk/tools/libclang/CXType.cpp (original) +++ cfe/trunk/tools/libclang/CXType.cpp Thu Jan 26 14:40:47 2017 @@ -452,7 +452,8 @@ try_again: break; case Type::Auto: - TP = cast<AutoType>(TP)->getDeducedType().getTypePtrOrNull(); + case Type::DeducedTemplateSpecialization: + TP = cast<DeducedType>(TP)->getDeducedType().getTypePtrOrNull(); if (TP) goto try_again; break; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits