summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/ASTContext.h7
-rw-r--r--include/clang/AST/RecursiveASTVisitor.h9
-rw-r--r--include/clang/AST/Type.h119
-rw-r--r--include/clang/AST/TypeLoc.h22
-rw-r--r--include/clang/AST/TypeNodes.def4
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td20
-rw-r--r--include/clang/Parse/Parser.h20
-rw-r--r--include/clang/Sema/DeclSpec.h7
-rw-r--r--include/clang/Sema/Sema.h1
-rw-r--r--include/clang/Serialization/ASTBitCodes.h4
-rw-r--r--lib/AST/ASTContext.cpp30
-rw-r--r--lib/AST/ASTImporter.cpp14
-rw-r--r--lib/AST/ExprConstant.cpp1
-rw-r--r--lib/AST/ItaniumMangle.cpp11
-rw-r--r--lib/AST/MicrosoftMangle.cpp11
-rw-r--r--lib/AST/Type.cpp30
-rw-r--r--lib/AST/TypePrinter.cpp19
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp1
-rw-r--r--lib/CodeGen/CodeGenFunction.cpp4
-rw-r--r--lib/CodeGen/CodeGenTypes.cpp3
-rw-r--r--lib/CodeGen/ItaniumCXXABI.cpp6
-rw-r--r--lib/Parse/ParseDecl.cpp10
-rw-r--r--lib/Parse/ParseDeclCXX.cpp9
-rw-r--r--lib/Parse/ParseExprCXX.cpp3
-rw-r--r--lib/Parse/Parser.cpp3
-rw-r--r--lib/Sema/SemaDecl.cpp84
-rw-r--r--lib/Sema/SemaExpr.cpp3
-rw-r--r--lib/Sema/SemaExprCXX.cpp19
-rw-r--r--lib/Sema/SemaLookup.cpp1
-rw-r--r--lib/Sema/SemaTemplate.cpp8
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp4
-rw-r--r--lib/Sema/SemaType.cpp99
-rw-r--r--lib/Sema/TreeTransform.h39
-rw-r--r--lib/Serialization/ASTReader.cpp13
-rw-r--r--lib/Serialization/ASTWriter.cpp14
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp2
-rw-r--r--test/CXX/drs/dr5xx.cpp16
-rw-r--r--test/Parser/backtrack-off-by-one.cpp9
-rw-r--r--test/Parser/cxx1z-class-template-argument-deduction.cpp131
-rw-r--r--test/SemaTemplate/temp_arg.cpp2
-rw-r--r--test/SemaTemplate/typename-specifier-3.cpp3
-rw-r--r--tools/libclang/CIndex.cpp9
-rw-r--r--tools/libclang/CXType.cpp3
43 files changed, 699 insertions, 128 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index 1c9ce82143..95429bf8ce 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -167,6 +167,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
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;
diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h
index 9bab3219ca..1cd71d299e 100644
--- a/include/clang/AST/RecursiveASTVisitor.h
+++ b/include/clang/AST/RecursiveASTVisitor.h
@@ -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, {})
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
index 614351f76b..06d34ad624 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -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
diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h
index 5b7d9e6e3c..a10b9792d9 100644
--- a/include/clang/AST/TypeLoc.h
+++ b/include/clang/AST/TypeLoc.h
@@ -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 {
diff --git a/include/clang/AST/TypeNodes.def b/include/clang/AST/TypeNodes.def
index 27ab21bf7f..9d1d09e2cc 100644
--- a/include/clang/AST/TypeNodes.def
+++ b/include/clang/AST/TypeNodes.def
@@ -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)
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 7f7ef1848a..5429b12bd0 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1870,16 +1870,20 @@ def err_illegal_decl_array_of_auto : Error<
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 : Error<
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">;
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index fe159022c2..52b0c1bcf2 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -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 {
diff --git a/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h
index 331fd0db67..7505c741a5 100644
--- a/include/clang/Sema/DeclSpec.h
+++ b/include/clang/Sema/DeclSpec.h
@@ -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:
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 1d3b27302b..63ca474af1 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -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);
diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h
index acbd6d1deb..3a4adc0c0b 100644
--- a/include/clang/Serialization/ASTBitCodes.h
+++ b/include/clang/Serialization/ASTBitCodes.h
@@ -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
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 5624758670..a8732d729c 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -1877,8 +1877,9 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
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::getVariableArrayDecayedType(QualType type) const {
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(QualType DeducedType, AutoTypeKeyword Keyword,
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::getObjCEncodingForTypeImpl(QualType T, std::string& S,
// 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 LHS, QualType RHS,
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:
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index c8397d458d..f80ce35df2 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -883,6 +883,20 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
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,
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 5fab58a5af..92c8107251 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -7004,6 +7004,7 @@ static int EvaluateBuiltinClassifyType(const CallExpr *E,
case Type::Vector:
case Type::ExtVector:
case Type::Auto:
+ case Type::DeducedTemplateSpecialization:
case Type::ObjCObject:
case Type::ObjCInterface:
case Type::ObjCObjectPointer:
diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp
index 41c057719b..4c1beaab10 100644
--- a/lib/AST/ItaniumMangle.cpp
+++ b/lib/AST/ItaniumMangle.cpp
@@ -1870,6 +1870,7 @@ bool CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty,
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 AutoType *T) {
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...)
diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp
index abe94786a3..a76d186747 100644
--- a/lib/AST/MicrosoftMangle.cpp
+++ b/lib/AST/MicrosoftMangle.cpp
@@ -2474,6 +2474,17 @@ void MicrosoftCXXNameMangler::mangleType(const AutoType *T, Qualifiers,
<< 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();
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 8a93f7c5d1..8f22a1b197 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -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 computeCachedProperties(const Type *T) {
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(const Type *T) {
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()) {
diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
index cccc908763..c4bc6a4ab5 100644
--- a/lib/AST/TypePrinter.cpp
+++ b/lib/AST/TypePrinter.cpp
@@ -189,6 +189,7 @@ bool TypePrinter::canPrefixQualifiers(const Type *T,
case Type::Elaborated:
case Type::TemplateTypeParm:
case Type::SubstTemplateTypeParmPack:
+ case Type::DeducedTemplateSpecialization:
case Type::TemplateSpecialization:
case Type::InjectedClassName:
case Type::DependentName:
@@ -888,6 +889,24 @@ void TypePrinter::printAutoAfter(const AutoType *T, raw_ostream &OS) {
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);
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index c3dd53f12e..c177a24162 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -2618,6 +2618,7 @@ llvm::DIType *CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile *Unit) {
case Type::Attributed:
case Type::Adjusted:
case Type::Decayed:
+ case Type::DeducedTemplateSpecialization:
case Type::Elaborated:
case Type::Paren:
case Type::SubstTemplateTypeParm:
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index 798d5b48fa..00bde1c5b2 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -200,7 +200,8 @@ TypeEvaluationKind CodeGenFunction::getEvaluationKind(QualType type) {
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::EmitVariablyModifiedType(QualType type) {
case Type::Typedef:
case Type::Decltype:
case Type::Auto:
+ case Type::DeducedTemplateSpecialization:
// Stop walking: nothing to do.
return;
diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp
index b95b4fff57..d2baeb4ea1 100644
--- a/lib/CodeGen/CodeGenTypes.cpp
+++ b/lib/CodeGen/CodeGenTypes.cpp
@@ -487,7 +487,8 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
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);
diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp
index 490fadbd1c..74aabeb253 100644
--- a/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/lib/CodeGen/ItaniumCXXABI.cpp
@@ -2815,7 +2815,8 @@ void ItaniumRTTIBuilder::BuildVTablePointer(const Type *Ty) {
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::BuildTypeInfo(QualType Ty, bool Force,
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");
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 255f27dbfb..6da61c689e 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -2884,7 +2884,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
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(DeclSpec &DS,
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.
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index 3f1fe7e06f..ca5a251b35 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -1144,10 +1144,11 @@ TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc,
// 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;
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index 383986470d..cfda2cddec 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -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) ||
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index 2f8ee0c068..8713bb2c23 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -1743,7 +1743,8 @@ bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(CXXScopeSpec &SS,
*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();
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index c9cf86f43c..3ed6ede53c 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -60,6 +60,11 @@ Sema::DeclGroupPtrTy Sema::ConvertDeclToDeclGroup(Decl *Ptr, Decl *OwnedType) {
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 CorrectionCandidateCallback {
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 CorrectionCandidateCallback {
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 CorrectionCandidateCallback {
private:
bool AllowInvalidDecl;
bool WantClassName;
- bool AllowClassTemplates;
+ bool AllowTemplates;
};
} // end anonymous namespace
@@ -252,7 +257,13 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
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 IdentifierInfo &II, SourceLocation NameLoc,
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 IdentifierInfo &II, SourceLocation NameLoc,
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 IdentifierInfo &II, SourceLocation NameLoc,
// 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 IdentifierInfo &II, SourceLocation NameLoc,
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 IdentifierInfo &II, SourceLocation NameLoc,
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(IdentifierInfo *&II,
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::deduceVarTypeFromInitializer(VarDecl *VDecl,
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))
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index be97e27ae6..4324239059 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -3976,7 +3976,8 @@ static void captureVariablyModifiedType(ASTContext &Context, QualType T,
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();
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 2bf1c73939..f4df3caf72 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -1255,9 +1255,19 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
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, bool UseGlobal,
// 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);
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index 2b35a3583e..84dc7799b2 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -2694,6 +2694,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) {
// 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
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 87764c3640..6a53009523 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -4439,6 +4439,11 @@ bool UnnamedLocalNoLinkageFinder::VisitAutoType(const AutoType *T) {
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(ElaboratedTypeKeyword Keyword,
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;
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index 3197647d8d..688d6bb8e6 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -1723,6 +1723,7 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
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 &Ctx, QualType T,
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.
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 29b2142679..e4995bd220 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -2778,12 +2778,20 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
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 GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
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 GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
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 GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
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 GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
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 GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
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 GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
// 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 GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
// 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 GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
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 GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
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 *GetFullTypeForDeclarator(TypeProcessingState &state,
// 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 *GetFullTypeForDeclarator(TypeProcessingState &state,
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 *GetFullTypeForDeclarator(TypeProcessingState &state,
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:
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 30d1b5b765..d27cd77040 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -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
@@ -5346,6 +5354,37 @@ QualType TreeTransform<Derived>::TransformAutoType(TypeLocBuilder &TLB,
}
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,
RecordTypeLoc TL) {
const RecordType *T = TL.getTypePtr();
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index 25a9b1081c..89d67df6e6 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -5651,6 +5651,14 @@ QualType ASTReader::readTypeRecord(unsigned Index) {
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(AutoTypeLoc TL) {
TL.setNameLoc(ReadSourceLocation());
}
+void TypeLocReader::VisitDeducedTemplateSpecializationTypeLoc(
+ DeducedTemplateSpecializationTypeLoc TL) {
+ TL.setTemplateNameLoc(ReadSourceLocation());
+}
+
void TypeLocReader::VisitRecordTypeLoc(RecordTypeLoc TL) {
TL.setNameLoc(ReadSourceLocation());
}
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index b2237a5fc1..9ba9d6ca70 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -349,6 +349,15 @@ void ASTTypeWriter::VisitAutoType(const AutoType *T) {
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(AutoTypeLoc TL) {
Record.AddSourceLocation(TL.getNameLoc());
}
+void TypeLocWriter::VisitDeducedTemplateSpecializationTypeLoc(
+ DeducedTemplateSpecializationTypeLoc TL) {
+ Record.AddSourceLocation(TL.getTemplateNameLoc());
+}
+
void TypeLocWriter::VisitRecordTypeLoc(RecordTypeLoc TL) {
Record.AddSourceLocation(TL.getNameLoc());
}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp
index 0cdf3c6e05..a260f99f5c 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp
@@ -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}}
};
diff --git a/test/CXX/drs/dr5xx.cpp b/test/CXX/drs/dr5xx.cpp
index 89e404f5fd..cdb75219b1 100644
--- a/test/CXX/drs/dr5xx.cpp
+++ b/test/CXX/drs/dr5xx.cpp
@@ -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}}
};
}
diff --git a/test/Parser/backtrack-off-by-one.cpp b/test/Parser/backtrack-off-by-one.cpp
index efb95a5a22..52e1c41478 100644
--- a/test/Parser/backtrack-off-by-one.cpp
+++ b/test/Parser/backtrack-off-by-one.cpp
@@ -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> {
};
diff --git a/test/Parser/cxx1z-class-template-argument-deduction.cpp b/test/Parser/cxx1z-class-template-argument-deduction.cpp
new file mode 100644
index 0000000000..e53d64f2ed
--- /dev/null
+++ b/test/Parser/cxx1z-class-template-argument-deduction.cpp
@@ -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}}
+}
diff --git a/test/SemaTemplate/temp_arg.cpp b/test/SemaTemplate/temp_arg.cpp
index 052c19ef63..df5bf875f3 100644
--- a/test/SemaTemplate/temp_arg.cpp
+++ b/test/SemaTemplate/temp_arg.cpp
@@ -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 {};
diff --git a/test/SemaTemplate/typename-specifier-3.cpp b/test/SemaTemplate/typename-specifier-3.cpp
index a463d88752..dfab5a0130 100644
--- a/test/SemaTemplate/typename-specifier-3.cpp
+++ b/test/SemaTemplate/typename-specifier-3.cpp
@@ -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}}
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index 4fa540d33c..6f4868d4b6 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -1640,6 +1640,15 @@ bool CursorVisitor::VisitAdjustedTypeLoc(AdjustedTypeLoc TL) {
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.
diff --git a/tools/libclang/CXType.cpp b/tools/libclang/CXType.cpp
index 66caf340d1..2eeeba4366 100644
--- a/tools/libclang/CXType.cpp
+++ b/tools/libclang/CXType.cpp
@@ -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;