summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/include/clang/AST/ASTContext.h7
-rw-r--r--clang/include/clang/AST/ASTNodeTraverser.h4
-rwxr-xr-xclang/include/clang/AST/DeclTemplate.h43
-rw-r--r--clang/include/clang/AST/PropertiesBase.td2
-rw-r--r--clang/include/clang/AST/RecursiveASTVisitor.h14
-rw-r--r--clang/include/clang/AST/TemplateBase.h7
-rw-r--r--clang/include/clang/AST/Type.h74
-rw-r--r--clang/include/clang/AST/TypeLoc.h138
-rw-r--r--clang/include/clang/AST/TypeProperties.td11
-rw-r--r--clang/include/clang/Basic/DiagnosticParseKinds.td2
-rw-r--r--clang/include/clang/Basic/DiagnosticSemaKinds.td12
-rw-r--r--clang/include/clang/Sema/DeclSpec.h72
-rw-r--r--clang/include/clang/Sema/Scope.h6
-rw-r--r--clang/include/clang/Sema/ScopeInfo.h20
-rw-r--r--clang/include/clang/Sema/Sema.h47
-rw-r--r--clang/lib/AST/ASTContext.cpp152
-rw-r--r--clang/lib/AST/ASTImporter.cpp18
-rw-r--r--clang/lib/AST/ASTStructuralEquivalence.cpp26
-rwxr-xr-xclang/lib/AST/DeclTemplate.cpp45
-rw-r--r--clang/lib/AST/ODRHash.cpp7
-rw-r--r--clang/lib/AST/TemplateBase.cpp2
-rw-r--r--clang/lib/AST/TextNodeDumper.cpp5
-rw-r--r--clang/lib/AST/Type.cpp36
-rw-r--r--clang/lib/AST/TypeLoc.cpp95
-rw-r--r--clang/lib/AST/TypePrinter.cpp29
-rw-r--r--clang/lib/Parse/ParseCXXInlineMethods.cpp4
-rw-r--r--clang/lib/Parse/ParseDecl.cpp73
-rw-r--r--clang/lib/Parse/ParseDeclCXX.cpp2
-rw-r--r--clang/lib/Parse/ParseTemplate.cpp5
-rw-r--r--clang/lib/Parse/ParseTentative.cpp21
-rw-r--r--clang/lib/Parse/Parser.cpp24
-rw-r--r--clang/lib/Sema/DeclSpec.cpp9
-rw-r--r--clang/lib/Sema/Sema.cpp15
-rw-r--r--clang/lib/Sema/SemaDecl.cpp39
-rw-r--r--clang/lib/Sema/SemaDeclCXX.cpp47
-rw-r--r--clang/lib/Sema/SemaLambda.cpp3
-rwxr-xr-xclang/lib/Sema/SemaTemplate.cpp190
-rw-r--r--clang/lib/Sema/SemaTemplateDeduction.cpp77
-rwxr-xr-xclang/lib/Sema/SemaTemplateInstantiateDecl.cpp10
-rw-r--r--clang/lib/Sema/SemaType.cpp231
-rw-r--r--clang/lib/Sema/TreeTransform.h137
-rw-r--r--clang/lib/Serialization/ASTReader.cpp11
-rw-r--r--clang/lib/Serialization/ASTReaderDecl.cpp22
-rw-r--r--clang/lib/Serialization/ASTWriter.cpp12
-rw-r--r--clang/lib/Serialization/ASTWriterDecl.cpp4
-rw-r--r--clang/test/AST/ast-dump-record-definition-data-json.cpp57
-rw-r--r--clang/test/CXX/dcl/dcl.fct/p17.cpp260
-rw-r--r--clang/test/CXX/dcl/dcl.spec/dcl.type/dcl.spec.auto/p6.cpp44
-rw-r--r--clang/test/CXX/expr/expr.prim/expr.prim.lambda/expr.prim.lambda.closure/p3.cpp6
-rw-r--r--clang/test/CXX/temp/temp.param/p10-2a.cpp25
-rw-r--r--clang/test/Parser/cxx2a-placeholder-type-constraint.cpp26
-rw-r--r--clang/test/SemaCXX/cxx1y-generic-lambdas.cpp2
-rw-r--r--clang/test/SemaTemplate/ms-delayed-default-template-args.cpp3
53 files changed, 1871 insertions, 362 deletions
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index fb269cef1ce..f8403cf13c4 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -88,6 +88,7 @@ class AtomicExpr;
class BlockExpr;
class BuiltinTemplateDecl;
class CharUnits;
+class ConceptDecl;
class CXXABI;
class CXXConstructorDecl;
class CXXMethodDecl;
@@ -211,7 +212,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
mutable llvm::FoldingSet<ObjCObjectPointerType> ObjCObjectPointerTypes;
mutable llvm::FoldingSet<DependentUnaryTransformType>
DependentUnaryTransformTypes;
- mutable llvm::FoldingSet<AutoType> AutoTypes;
+ mutable llvm::ContextualFoldingSet<AutoType, ASTContext&> AutoTypes;
mutable llvm::FoldingSet<DeducedTemplateSpecializationType>
DeducedTemplateSpecializationTypes;
mutable llvm::FoldingSet<AtomicType> AtomicTypes;
@@ -1542,7 +1543,9 @@ public:
/// C++11 deduced auto type.
QualType getAutoType(QualType DeducedType, AutoTypeKeyword Keyword,
- bool IsDependent, bool IsPack = false) const;
+ bool IsDependent, bool IsPack = false,
+ ConceptDecl *TypeConstraintConcept = nullptr,
+ ArrayRef<TemplateArgument> TypeConstraintArgs ={}) const;
/// C++11 deduction pattern for 'auto' type.
QualType getAutoDeductType() const;
diff --git a/clang/include/clang/AST/ASTNodeTraverser.h b/clang/include/clang/AST/ASTNodeTraverser.h
index e0ebb020e69..9ebf64a12af 100644
--- a/clang/include/clang/AST/ASTNodeTraverser.h
+++ b/clang/include/clang/AST/ASTNodeTraverser.h
@@ -548,8 +548,8 @@ public:
}
void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D) {
- if (const auto *TC = D->getPlaceholderTypeConstraint())
- Visit(TC->getImmediatelyDeclaredConstraint());
+ if (const auto *E = D->getPlaceholderTypeConstraint())
+ Visit(E);
if (D->hasDefaultArgument())
Visit(D->getDefaultArgument(), SourceRange(),
D->getDefaultArgStorage().getInheritedFrom(),
diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h
index 7a55d04a0f3..7a9f623d815 100755
--- a/clang/include/clang/AST/DeclTemplate.h
+++ b/clang/include/clang/AST/DeclTemplate.h
@@ -1102,6 +1102,17 @@ public:
/// template.
ArrayRef<TemplateArgument> getInjectedTemplateArgs();
+ /// Return whether this function template is an abbreviated function template,
+ /// e.g. `void foo(auto x)` or `template<typename T> void foo(auto x)`
+ bool isAbbreviated() const {
+ // Since the invented template parameters generated from 'auto' parameters
+ // are either appended to the end of the explicit template parameter list or
+ // form a new template paramter list, we can simply observe the last
+ // parameter to determine if such a thing happened.
+ const TemplateParameterList *TPL = getTemplateParameters();
+ return TPL->getParam(TPL->size() - 1)->isImplicit();
+ }
+
/// Merge \p Prev with our RedeclarableTemplateDecl::Common.
void mergePrevDecl(FunctionTemplateDecl *Prev);
@@ -1215,7 +1226,6 @@ public:
bool ParameterPack,
bool HasTypeConstraint = false,
Optional<unsigned> NumExpanded = None);
-
static TemplateTypeParmDecl *CreateDeserialized(const ASTContext &C,
unsigned ID);
static TemplateTypeParmDecl *CreateDeserialized(const ASTContext &C,
@@ -1374,7 +1384,8 @@ class NonTypeTemplateParmDecl final
: public DeclaratorDecl,
protected TemplateParmPosition,
private llvm::TrailingObjects<NonTypeTemplateParmDecl,
- std::pair<QualType, TypeSourceInfo *>> {
+ std::pair<QualType, TypeSourceInfo *>,
+ Expr *> {
friend class ASTDeclReader;
friend TrailingObjects;
@@ -1429,10 +1440,12 @@ public:
ArrayRef<TypeSourceInfo *> ExpandedTInfos);
static NonTypeTemplateParmDecl *CreateDeserialized(ASTContext &C,
- unsigned ID);
+ unsigned ID,
+ bool HasTypeConstraint);
static NonTypeTemplateParmDecl *CreateDeserialized(ASTContext &C,
unsigned ID,
- unsigned NumExpandedTypes);
+ unsigned NumExpandedTypes,
+ bool HasTypeConstraint);
using TemplateParmPosition::getDepth;
using TemplateParmPosition::setDepth;
@@ -1543,20 +1556,22 @@ public:
return TypesAndInfos[I].second;
}
- /// Return the type-constraint in the placeholder type of this non-type
+ /// Return the constraint introduced by the placeholder type of this non-type
/// template parameter (if any).
- TypeConstraint *getPlaceholderTypeConstraint() const {
- // TODO: Concepts: Implement once we have actual placeholders with type
- // constraints.
- return nullptr;
+ Expr *getPlaceholderTypeConstraint() const {
+ return hasPlaceholderTypeConstraint() ? *getTrailingObjects<Expr *>() :
+ nullptr;
+ }
+
+ void setPlaceholderTypeConstraint(Expr *E) {
+ *getTrailingObjects<Expr *>() = E;
}
/// Determine whether this non-type template parameter's type has a
/// placeholder with a type-constraint.
bool hasPlaceholderTypeConstraint() const {
- // TODO: Concepts: Implement once we have actual placeholders with type
- // constraints.
- return false;
+ auto *AT = getType()->getContainedAutoType();
+ return AT && AT->isConstrained();
}
/// \brief Get the associated-constraints of this template parameter.
@@ -1566,8 +1581,8 @@ public:
/// Use this instead of getPlaceholderImmediatelyDeclaredConstraint for
/// concepts APIs that accept an ArrayRef of constraint expressions.
void getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const {
- if (TypeConstraint *TC = getPlaceholderTypeConstraint())
- AC.push_back(TC->getImmediatelyDeclaredConstraint());
+ if (Expr *E = getPlaceholderTypeConstraint())
+ AC.push_back(E);
}
// Implement isa/cast/dyncast/etc.
diff --git a/clang/include/clang/AST/PropertiesBase.td b/clang/include/clang/AST/PropertiesBase.td
index 9aacdb9fee3..ba0f237a3bc 100644
--- a/clang/include/clang/AST/PropertiesBase.td
+++ b/clang/include/clang/AST/PropertiesBase.td
@@ -99,6 +99,8 @@ def DeclRef : RefPropertyType<"Decl"> { let ConstWhenWriting = 1; }
SubclassPropertyType<"TagDecl", DeclRef>;
def TemplateDeclRef :
SubclassPropertyType<"TemplateDecl", DeclRef>;
+ def ConceptDeclRef :
+ SubclassPropertyType<"ConceptDecl", DeclRef>;
def TemplateTypeParmDeclRef :
SubclassPropertyType<"TemplateTypeParmDecl", DeclRef>;
def TemplateTemplateParmDeclRef :
diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h
index 4633122aba4..86521d82c6f 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -1040,7 +1040,13 @@ DEF_TRAVERSE_TYPE(UnaryTransformType, {
TRY_TO(TraverseType(T->getUnderlyingType()));
})
-DEF_TRAVERSE_TYPE(AutoType, { TRY_TO(TraverseType(T->getDeducedType())); })
+DEF_TRAVERSE_TYPE(AutoType, {
+ TRY_TO(TraverseType(T->getDeducedType()));
+ if (T->isConstrained()) {
+ TRY_TO(TraverseDecl(T->getTypeConstraintConcept()));
+ TRY_TO(TraverseTemplateArguments(T->getArgs(), T->getNumArgs()));
+ }
+})
DEF_TRAVERSE_TYPE(DeducedTemplateSpecializationType, {
TRY_TO(TraverseTemplateName(T->getTemplateName()));
TRY_TO(TraverseType(T->getDeducedType()));
@@ -1287,6 +1293,12 @@ DEF_TRAVERSE_TYPELOC(UnaryTransformType, {
DEF_TRAVERSE_TYPELOC(AutoType, {
TRY_TO(TraverseType(TL.getTypePtr()->getDeducedType()));
+ if (TL.isConstrained()) {
+ TRY_TO(TraverseNestedNameSpecifierLoc(TL.getNestedNameSpecifierLoc()));
+ TRY_TO(TraverseDeclarationNameInfo(TL.getConceptNameInfo()));
+ for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I)
+ TRY_TO(TraverseTemplateArgumentLoc(TL.getArgLoc(I)));
+ }
})
DEF_TRAVERSE_TYPELOC(DeducedTemplateSpecializationType, {
diff --git a/clang/include/clang/AST/TemplateBase.h b/clang/include/clang/AST/TemplateBase.h
index 058a5bc0a06..93f7b62b8ae 100644
--- a/clang/include/clang/AST/TemplateBase.h
+++ b/clang/include/clang/AST/TemplateBase.h
@@ -637,7 +637,7 @@ public:
}
static const ASTTemplateArgumentListInfo *
- Create(ASTContext &C, const TemplateArgumentListInfo &List);
+ Create(const ASTContext &C, const TemplateArgumentListInfo &List);
};
/// Represents an explicit template argument list in C++, e.g.,
@@ -702,6 +702,11 @@ inline const TemplateArgument &
return getArgs()[Idx];
}
+inline const TemplateArgument &AutoType::getArg(unsigned Idx) const {
+ assert(Idx < getNumArgs() && "Template argument out of range");
+ return getArgs()[Idx];
+}
+
} // namespace clang
#endif // LLVM_CLANG_AST_TEMPLATEBASE_H
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index f5955c45faf..abc8136653f 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -58,6 +58,7 @@ namespace clang {
class ExtQuals;
class QualType;
+class ConceptDecl;
class TagDecl;
class Type;
@@ -1683,6 +1684,15 @@ protected:
/// Was this placeholder type spelled as 'auto', 'decltype(auto)',
/// or '__auto_type'? AutoTypeKeyword value.
unsigned Keyword : 2;
+
+ /// The number of template arguments in the type-constraints, which is
+ /// expected to be able to hold at least 1024 according to [implimits].
+ /// However as this limit is somewhat easy to hit with template
+ /// metaprogramming we'd prefer to keep it as large as possible.
+ /// At the moment it has been left as a non-bitfield since this type
+ /// safely fits in 64 bits as an unsigned, so there is no reason to
+ /// introduce the performance impact of a bitfield.
+ unsigned NumArgs;
};
class SubstTemplateTypeParmPackTypeBitfields {
@@ -4814,8 +4824,7 @@ public:
/// 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.
+/// class template types, and constrained type names.
///
/// These types are usually a placeholder for a deduced type. However, before
/// the initializer is attached, or (usually) if the initializer is
@@ -4860,18 +4869,50 @@ public:
}
};
-/// Represents a C++11 auto or C++14 decltype(auto) type.
-class AutoType : public DeducedType, public llvm::FoldingSetNode {
+/// Represents a C++11 auto or C++14 decltype(auto) type, possibly constrained
+/// by a type-constraint.
+class alignas(8) AutoType : public DeducedType, public llvm::FoldingSetNode {
friend class ASTContext; // ASTContext creates these
+ ConceptDecl *TypeConstraintConcept;
+
AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword,
- bool IsDeducedAsDependent, bool IsDeducedAsPack)
- : DeducedType(Auto, DeducedAsType, IsDeducedAsDependent,
- IsDeducedAsDependent, IsDeducedAsPack) {
- AutoTypeBits.Keyword = (unsigned)Keyword;
+ bool IsDeducedAsDependent, bool IsDeducedAsPack, ConceptDecl *CD,
+ ArrayRef<TemplateArgument> TypeConstraintArgs);
+
+ const TemplateArgument *getArgBuffer() const {
+ return reinterpret_cast<const TemplateArgument*>(this+1);
+ }
+
+ TemplateArgument *getArgBuffer() {
+ return reinterpret_cast<TemplateArgument*>(this+1);
}
public:
+ /// Retrieve the template arguments.
+ const TemplateArgument *getArgs() const {
+ return getArgBuffer();
+ }
+
+ /// Retrieve the number of template arguments.
+ unsigned getNumArgs() const {
+ return AutoTypeBits.NumArgs;
+ }
+
+ const TemplateArgument &getArg(unsigned Idx) const; // in TemplateBase.h
+
+ ArrayRef<TemplateArgument> getTypeConstraintArguments() const {
+ return {getArgs(), getNumArgs()};
+ }
+
+ ConceptDecl *getTypeConstraintConcept() const {
+ return TypeConstraintConcept;
+ }
+
+ bool isConstrained() const {
+ return TypeConstraintConcept != nullptr;
+ }
+
bool isDecltypeAuto() const {
return getKeyword() == AutoTypeKeyword::DecltypeAuto;
}
@@ -4880,18 +4921,15 @@ public:
return (AutoTypeKeyword)AutoTypeBits.Keyword;
}
- void Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getDeducedType(), getKeyword(), isDependentType(),
- containsUnexpandedParameterPack());
+ void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) {
+ Profile(ID, Context, getDeducedType(), getKeyword(), isDependentType(),
+ getTypeConstraintConcept(), getTypeConstraintArguments());
}
- static void Profile(llvm::FoldingSetNodeID &ID, QualType Deduced,
- AutoTypeKeyword Keyword, bool IsDependent, bool IsPack) {
- ID.AddPointer(Deduced.getAsOpaquePtr());
- ID.AddInteger((unsigned)Keyword);
- ID.AddBoolean(IsDependent);
- ID.AddBoolean(IsPack);
- }
+ static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
+ QualType Deduced, AutoTypeKeyword Keyword,
+ bool IsDependent, ConceptDecl *CD,
+ ArrayRef<TemplateArgument> Arguments);
static bool classof(const Type *T) {
return T->getTypeClass() == Auto;
diff --git a/clang/include/clang/AST/TypeLoc.h b/clang/include/clang/AST/TypeLoc.h
index c3baaa3e417..3fc53d823c3 100644
--- a/clang/include/clang/AST/TypeLoc.h
+++ b/clang/include/clang/AST/TypeLoc.h
@@ -14,6 +14,7 @@
#ifndef LLVM_CLANG_AST_TYPELOC_H
#define LLVM_CLANG_AST_TYPELOC_H
+#include "clang/AST/DeclarationName.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/TemplateBase.h"
#include "clang/AST/Type.h"
@@ -34,6 +35,7 @@ namespace clang {
class Attr;
class ASTContext;
class CXXRecordDecl;
+class ConceptDecl;
class Expr;
class ObjCInterfaceDecl;
class ObjCProtocolDecl;
@@ -181,6 +183,11 @@ public:
/// AttributedTypeLoc, for those type attributes that behave as qualifiers
TypeLoc findExplicitQualifierLoc() const;
+ /// Get the typeloc of an 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.
+ AutoTypeLoc getContainedAutoTypeLoc() const;
+
/// Initializes this to state that every location in this
/// type is the given location.
///
@@ -1923,8 +1930,137 @@ class DeducedTypeLoc
: public InheritingConcreteTypeLoc<TypeSpecTypeLoc, DeducedTypeLoc,
DeducedType> {};
+struct AutoTypeLocInfo : TypeSpecLocInfo {
+ NestedNameSpecifierLoc NestedNameSpec;
+ SourceLocation TemplateKWLoc;
+ SourceLocation ConceptNameLoc;
+ NamedDecl *FoundDecl;
+ SourceLocation LAngleLoc;
+ SourceLocation RAngleLoc;
+};
+
class AutoTypeLoc
- : public InheritingConcreteTypeLoc<DeducedTypeLoc, AutoTypeLoc, AutoType> {
+ : public ConcreteTypeLoc<DeducedTypeLoc,
+ AutoTypeLoc,
+ AutoType,
+ AutoTypeLocInfo> {
+public:
+ AutoTypeKeyword getAutoKeyword() const {
+ return getTypePtr()->getKeyword();
+ }
+
+ bool isConstrained() const {
+ return getTypePtr()->isConstrained();
+ }
+
+ const NestedNameSpecifierLoc &getNestedNameSpecifierLoc() const {
+ return getLocalData()->NestedNameSpec;
+ }
+
+ void setNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {
+ getLocalData()->NestedNameSpec = NNS;
+ }
+
+ SourceLocation getTemplateKWLoc() const {
+ return getLocalData()->TemplateKWLoc;
+ }
+
+ void setTemplateKWLoc(SourceLocation Loc) {
+ getLocalData()->TemplateKWLoc = Loc;
+ }
+
+ SourceLocation getConceptNameLoc() const {
+ return getLocalData()->ConceptNameLoc;
+ }
+
+ void setConceptNameLoc(SourceLocation Loc) {
+ getLocalData()->ConceptNameLoc = Loc;
+ }
+
+ NamedDecl *getFoundDecl() const {
+ return getLocalData()->FoundDecl;
+ }
+
+ void setFoundDecl(NamedDecl *D) {
+ getLocalData()->FoundDecl = D;
+ }
+
+ ConceptDecl *getNamedConcept() const {
+ return getTypePtr()->getTypeConstraintConcept();
+ }
+
+ DeclarationNameInfo getConceptNameInfo() const;
+
+ bool hasExplicitTemplateArgs() const {
+ return getLocalData()->LAngleLoc.isValid();
+ }
+
+ SourceLocation getLAngleLoc() const {
+ return this->getLocalData()->LAngleLoc;
+ }
+
+ void setLAngleLoc(SourceLocation Loc) {
+ this->getLocalData()->LAngleLoc = Loc;
+ }
+
+ SourceLocation getRAngleLoc() const {
+ return this->getLocalData()->RAngleLoc;
+ }
+
+ void setRAngleLoc(SourceLocation Loc) {
+ this->getLocalData()->RAngleLoc = Loc;
+ }
+
+ unsigned getNumArgs() const {
+ return getTypePtr()->getNumArgs();
+ }
+
+ void setArgLocInfo(unsigned i, TemplateArgumentLocInfo AI) {
+ getArgInfos()[i] = AI;
+ }
+
+ TemplateArgumentLocInfo getArgLocInfo(unsigned i) const {
+ return getArgInfos()[i];
+ }
+
+ TemplateArgumentLoc getArgLoc(unsigned i) const {
+ return TemplateArgumentLoc(getTypePtr()->getTypeConstraintArguments()[i],
+ getArgLocInfo(i));
+ }
+
+ SourceRange getLocalSourceRange() const {
+ return{
+ isConstrained()
+ ? (getNestedNameSpecifierLoc()
+ ? getNestedNameSpecifierLoc().getBeginLoc()
+ : (getTemplateKWLoc().isValid()
+ ? getTemplateKWLoc()
+ : getConceptNameLoc()))
+ : getNameLoc(),
+ getNameLoc()
+ };
+ }
+
+ void copy(AutoTypeLoc Loc) {
+ unsigned size = getFullDataSize();
+ assert(size == Loc.getFullDataSize());
+ memcpy(Data, Loc.Data, size);
+ }
+
+ void initializeLocal(ASTContext &Context, SourceLocation Loc);
+
+ unsigned getExtraLocalDataSize() const {
+ return getNumArgs() * sizeof(TemplateArgumentLocInfo);
+ }
+
+ unsigned getExtraLocalDataAlignment() const {
+ return alignof(TemplateArgumentLocInfo);
+ }
+
+private:
+ TemplateArgumentLocInfo *getArgInfos() const {
+ return static_cast<TemplateArgumentLocInfo*>(getExtraLocalData());
+ }
};
class DeducedTemplateSpecializationTypeLoc
diff --git a/clang/include/clang/AST/TypeProperties.td b/clang/include/clang/AST/TypeProperties.td
index 4df2e2f77e2..3cf56e5a562 100644
--- a/clang/include/clang/AST/TypeProperties.td
+++ b/clang/include/clang/AST/TypeProperties.td
@@ -395,6 +395,13 @@ let Class = AutoType in {
def : Property<"keyword", AutoTypeKeyword> {
let Read = [{ node->getKeyword() }];
}
+ def : Property<"typeConstraintConcept", Optional<ConceptDeclRef>> {
+ let Read = [{ makeOptionalFromPointer(
+ const_cast<const ConceptDecl*>(node->getTypeConstraintConcept())) }];
+ }
+ def : Property<"typeConstraintArguments", Array<TemplateArgument>> {
+ let Read = [{ node->getTypeConstraintArguments() }];
+ }
// FIXME: better enumerated value
// Only really required when the deduced type is null
def : Property<"dependence", UInt32> {
@@ -406,7 +413,9 @@ let Class = AutoType in {
def : Creator<[{
return ctx.getAutoType(makeNullableFromOptional(deducedType), keyword,
/*isDependentWithoutDeducedType*/ dependence > 0,
- /*isPackWithoutDeducedType*/ dependence > 1);
+ /*isPackWithoutDeducedType*/ dependence > 1,
+ makePointerFromOptional(typeConstraintConcept),
+ typeConstraintArguments);
}]>;
}
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index 105ed7bf6c8..04b103e3087 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1371,6 +1371,8 @@ def err_concept_definition_not_identifier : Error<
def ext_concept_legacy_bool_keyword : ExtWarn<
"ISO C++2a does not permit the 'bool' keyword after 'concept'">,
InGroup<DiagGroup<"concepts-ts-compat">>;
+def err_placeholder_expected_auto_or_decltype_auto : Error<
+ "expected 'auto' or 'decltype(auto)' after concept name">;
}
} // end of Parser diagnostics
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 82649ddf8ab..7636d04a34c 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2102,11 +2102,8 @@ def err_auto_not_allowed : Error<
"|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"
- "|in template parameter|in friend declaration"
- "|in requires expression parameter}1">;
-def err_auto_not_allowed_in_return_type_requirement : Error<
- "%select{'auto'|'decltype(auto)'|'__auto_type'}0 not allowed in expression "
- "type requirement">;
+ "|in template parameter|in friend declaration|in function prototype that is "
+ "not a function declaration|in requires expression parameter}1">;
def err_dependent_deduced_tst : Error<
"typename specifier refers to "
"%select{class template|function template|variable template|alias template|"
@@ -2655,6 +2652,9 @@ def note_ambiguous_atomic_constraints : Note<
"same concept">;
def note_ambiguous_atomic_constraints_similar_expression : Note<
"similar constraint expression here">;
+def err_unsupported_placeholder_constraint : Error<
+ "constrained placeholder types other than simple 'auto' on non-type template "
+ "parameters not supported yet">;
def err_template_different_requires_clause : Error<
"requires clause differs in template redeclaration">;
@@ -2669,6 +2669,8 @@ def err_type_constraint_non_type_concept : Error<
def err_type_constraint_missing_arguments : Error<
"%0 requires more than 1 template argument; provide the remaining arguments "
"explicitly to use it here">;
+def err_placeholder_constraints_not_satisfied : Error<
+ "deduced type %0 does not satisfy %1">;
// C++11 char16_t/char32_t
def warn_cxx98_compat_unicode_type : Warning<
diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h
index 1222549161e..1559b51ea77 100644
--- a/clang/include/clang/Sema/DeclSpec.h
+++ b/clang/include/clang/Sema/DeclSpec.h
@@ -349,6 +349,7 @@ private:
unsigned TypeSpecOwned : 1;
unsigned TypeSpecPipe : 1;
unsigned TypeSpecSat : 1;
+ unsigned ConstrainedAuto : 1;
// type-qualifiers
unsigned TypeQualifiers : 5; // Bitwise OR of TQ.
@@ -369,6 +370,7 @@ private:
UnionParsedType TypeRep;
Decl *DeclRep;
Expr *ExprRep;
+ TemplateIdAnnotation *TemplateIdRep;
};
/// ExplicitSpecifier - Store information about explicit spicifer.
@@ -413,6 +415,9 @@ private:
static bool isExprRep(TST T) {
return (T == TST_typeofExpr || T == TST_decltype);
}
+ static bool isTemplateIdRep(TST T) {
+ return (T == TST_auto || T == TST_decltype_auto);
+ }
DeclSpec(const DeclSpec &) = delete;
void operator=(const DeclSpec &) = delete;
@@ -430,7 +435,8 @@ public:
TypeSpecComplex(TSC_unspecified), TypeSpecSign(TSS_unspecified),
TypeSpecType(TST_unspecified), TypeAltiVecVector(false),
TypeAltiVecPixel(false), TypeAltiVecBool(false), TypeSpecOwned(false),
- TypeSpecPipe(false), TypeSpecSat(false), TypeQualifiers(TQ_unspecified),
+ TypeSpecPipe(false), TypeSpecSat(false), ConstrainedAuto(false),
+ TypeQualifiers(TQ_unspecified),
FS_inline_specified(false), FS_forceinline_specified(false),
FS_virtual_specified(false), FS_noreturn_specified(false),
Friend_specified(false), ConstexprSpecifier(CSK_unspecified),
@@ -478,6 +484,7 @@ public:
bool isTypeRep() const { return isTypeRep((TST) TypeSpecType); }
bool isTypeSpecPipe() const { return TypeSpecPipe; }
bool isTypeSpecSat() const { return TypeSpecSat; }
+ bool isConstrainedAuto() const { return ConstrainedAuto; }
ParsedType getRepAsType() const {
assert(isTypeRep((TST) TypeSpecType) && "DeclSpec does not store a type");
@@ -491,6 +498,11 @@ public:
assert(isExprRep((TST) TypeSpecType) && "DeclSpec does not store an expr");
return ExprRep;
}
+ TemplateIdAnnotation *getRepAsTemplateId() const {
+ assert(isTemplateIdRep((TST) TypeSpecType) &&
+ "DeclSpec does not store a template id");
+ return TemplateIdRep;
+ }
CXXScopeSpec &getTypeSpecScope() { return TypeScope; }
const CXXScopeSpec &getTypeSpecScope() const { return TypeScope; }
@@ -666,6 +678,9 @@ public:
SourceLocation TagNameLoc, const char *&PrevSpec,
unsigned &DiagID, Decl *Rep, bool Owned,
const PrintingPolicy &Policy);
+ bool SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec,
+ unsigned &DiagID, TemplateIdAnnotation *Rep,
+ const PrintingPolicy &Policy);
bool SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec,
unsigned &DiagID, Expr *Rep,
@@ -1831,6 +1846,14 @@ private:
/// requires-clause, or null if no such clause was specified.
Expr *TrailingRequiresClause;
+ /// If this declarator declares a template, its template parameter lists.
+ ArrayRef<TemplateParameterList *> TemplateParameterLists;
+
+ /// If the declarator declares an abbreviated function template, the innermost
+ /// template parameter list containing the invented and explicit template
+ /// parameters (if any).
+ TemplateParameterList *InventedTemplateParameterList;
+
#ifndef _MSC_VER
union {
#endif
@@ -1861,7 +1884,8 @@ public:
Redeclaration(false), Extension(false), ObjCIvar(false),
ObjCWeakProperty(false), InlineStorageUsed(false),
Attrs(ds.getAttributePool().getFactory()), AsmLabel(nullptr),
- TrailingRequiresClause(nullptr) {}
+ TrailingRequiresClause(nullptr),
+ InventedTemplateParameterList(nullptr) {}
~Declarator() {
clear();
@@ -2429,6 +2453,30 @@ public:
return TrailingRequiresClause != nullptr;
}
+ /// Sets the template parameter lists that preceded the declarator.
+ void setTemplateParameterLists(ArrayRef<TemplateParameterList *> TPLs) {
+ TemplateParameterLists = TPLs;
+ }
+
+ /// The template parameter lists that preceded the declarator.
+ ArrayRef<TemplateParameterList *> getTemplateParameterLists() const {
+ return TemplateParameterLists;
+ }
+
+ /// Sets the template parameter list generated from the explicit template
+ /// parameters along with any invented template parameters from
+ /// placeholder-typed parameters.
+ void setInventedTemplateParameterList(TemplateParameterList *Invented) {
+ InventedTemplateParameterList = Invented;
+ }
+
+ /// The template parameter list generated from the explicit template
+ /// parameters along with any invented template parameters from
+ /// placeholder-typed parameters, if there were any such parameters.
+ TemplateParameterList * getInventedTemplateParameterList() const {
+ return InventedTemplateParameterList;
+ }
+
/// takeAttributes - Takes attributes from the given parsed-attributes
/// set and add them to this declarator.
///
@@ -2629,6 +2677,26 @@ struct LambdaIntroducer {
}
};
+struct InventedTemplateParameterInfo {
+ /// The number of parameters in the template parameter list that were
+ /// explicitly specified by the user, as opposed to being invented by use
+ /// of an auto parameter.
+ unsigned NumExplicitTemplateParams = 0;
+
+ /// If this is a generic lambda or abbreviated function template, use this
+ /// as the depth of each 'auto' parameter, during initial AST construction.
+ unsigned AutoTemplateParameterDepth = 0;
+
+ /// Store the list of the template parameters for a generic lambda or an
+ /// abbreviated function template.
+ /// If this is a generic lambda or abbreviated function template, this holds
+ /// the explicit template parameters followed by the auto parameters
+ /// converted into TemplateTypeParmDecls.
+ /// It can be used to construct the generic lambda or abbreviated template's
+ /// template parameter list during initial AST construction.
+ SmallVector<NamedDecl*, 4> TemplateParams;
+};
+
} // end namespace clang
#endif // LLVM_CLANG_SEMA_DECLSPEC_H
diff --git a/clang/include/clang/Sema/Scope.h b/clang/include/clang/Sema/Scope.h
index 7848df8f70d..6133425a42a 100644
--- a/clang/include/clang/Sema/Scope.h
+++ b/clang/include/clang/Sema/Scope.h
@@ -385,6 +385,12 @@ public:
return getFlags() & Scope::FunctionPrototypeScope;
}
+ /// isFunctionDeclarationScope - Return true if this scope is a
+ /// function prototype scope.
+ bool isFunctionDeclarationScope() const {
+ return getFlags() & Scope::FunctionDeclarationScope;
+ }
+
/// isAtCatchScope - Return true if this scope is \@catch.
bool isAtCatchScope() const {
return getFlags() & Scope::AtCatchScope;
diff --git a/clang/include/clang/Sema/ScopeInfo.h b/clang/include/clang/Sema/ScopeInfo.h
index 4f7534f9ef1..3c4847a2932 100644
--- a/clang/include/clang/Sema/ScopeInfo.h
+++ b/clang/include/clang/Sema/ScopeInfo.h
@@ -22,6 +22,7 @@
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Sema/CleanupInfo.h"
+#include "clang/Sema/DeclSpec.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseMapInfo.h"
#include "llvm/ADT/MapVector.h"
@@ -789,7 +790,8 @@ public:
}
};
-class LambdaScopeInfo final : public CapturingScopeInfo {
+class LambdaScopeInfo final :
+ public CapturingScopeInfo, public InventedTemplateParameterInfo {
public:
/// The class that describes the lambda.
CXXRecordDecl *Lambda = nullptr;
@@ -823,25 +825,9 @@ public:
/// Packs introduced by this lambda, if any.
SmallVector<NamedDecl*, 4> LocalPacks;
- /// If this is a generic lambda, use this as the depth of
- /// each 'auto' parameter, during initial AST construction.
- unsigned AutoTemplateParameterDepth = 0;
-
- /// The number of parameters in the template parameter list that were
- /// explicitly specified by the user, as opposed to being invented by use
- /// of an auto parameter.
- unsigned NumExplicitTemplateParams = 0;
-
/// Source range covering the explicit template parameter list (if it exists).
SourceRange ExplicitTemplateParamsRange;
- /// Store the list of the template parameters for a generic lambda.
- /// If this is a generic lambda, this holds the explicit template parameters
- /// followed by the auto parameters converted into TemplateTypeParmDecls.
- /// It can be used to construct the generic lambda's template parameter list
- /// during initial AST construction.
- SmallVector<NamedDecl*, 4> TemplateParams;
-
/// If this is a generic lambda, and the template parameter
/// list has been created (from the TemplateParams) then store
/// a reference to it (cache it to avoid reconstructing it).
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index c94027cf56d..a88dd281448 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -620,6 +620,13 @@ public:
/// function, block, and method scopes that are currently active.
SmallVector<sema::FunctionScopeInfo *, 4> FunctionScopes;
+ /// Stack containing information needed when in C++2a an 'auto' is encountered
+ /// in a function declaration parameter type specifier in order to invent a
+ /// corresponding template parameter in the enclosing abbreviated function
+ /// template. This information is also present in LambdaScopeInfo, stored in
+ /// the FunctionScopes stack.
+ SmallVector<InventedTemplateParameterInfo, 4> InventedParameterInfos;
+
typedef LazyVector<TypedefNameDecl *, ExternalSemaSource,
&ExternalSemaSource::ReadExtVectorDecls, 2, 2>
ExtVectorDeclsType;
@@ -1425,6 +1432,11 @@ public:
/// Retrieve the module loader associated with the preprocessor.
ModuleLoader &getModuleLoader() const;
+ /// Invent a new identifier for parameters of abbreviated templates.
+ IdentifierInfo *
+ InventAbbreviatedTemplateParameterTypeName(IdentifierInfo *ParamName,
+ unsigned Index);
+
void emitAndClearUnusedLocalTypedefWarnings();
enum TUFragmentKind {
@@ -1519,6 +1531,15 @@ public:
/// WeakTopLevelDeclDecls - access to \#pragma weak-generated Decls
SmallVectorImpl<Decl *> &WeakTopLevelDecls() { return WeakTopLevelDecl; }
+ /// Called before parsing a function declarator belonging to a function
+ /// declaration.
+ void ActOnStartFunctionDeclarationDeclarator(Declarator &D,
+ unsigned TemplateParameterDepth);
+
+ /// Called after parsing a function declarator belonging to a function
+ /// declaration.
+ void ActOnFinishFunctionDeclarationDeclarator(Declarator &D);
+
void ActOnComment(SourceRange Comment);
//===--------------------------------------------------------------------===//
@@ -1922,6 +1943,8 @@ public:
NC_FunctionTemplate,
/// The name was classified as an ADL-only function template name.
NC_UndeclaredTemplate,
+ /// The name was classified as a concept name.
+ NC_Concept,
};
class NameClassification {
@@ -1986,6 +2009,12 @@ public:
return Result;
}
+ static NameClassification Concept(TemplateName Name) {
+ NameClassification Result(NC_Concept);
+ Result.Template = Name;
+ return Result;
+ }
+
static NameClassification UndeclaredTemplate(TemplateName Name) {
NameClassification Result(NC_UndeclaredTemplate);
Result.Template = Name;
@@ -2011,7 +2040,8 @@ public:
TemplateName getTemplateName() const {
assert(Kind == NC_TypeTemplate || Kind == NC_FunctionTemplate ||
- Kind == NC_VarTemplate || Kind == NC_UndeclaredTemplate);
+ Kind == NC_VarTemplate || Kind == NC_Concept ||
+ Kind == NC_UndeclaredTemplate);
return Template;
}
@@ -2023,6 +2053,8 @@ public:
return TNK_Function_template;
case NC_VarTemplate:
return TNK_Var_template;
+ case NC_Concept:
+ return TNK_Concept_template;
case NC_UndeclaredTemplate:
return TNK_Undeclared_template;
default:
@@ -6882,6 +6914,10 @@ public:
TemplateTypeParmDecl *ConstrainedParameter,
SourceLocation EllipsisLoc);
+ bool AttachTypeConstraint(AutoTypeLoc TL,
+ NonTypeTemplateParmDecl *ConstrainedParameter,
+ SourceLocation EllipsisLoc);
+
QualType CheckNonTypeTemplateParameterType(TypeSourceInfo *&TSI,
SourceLocation Loc);
QualType CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc);
@@ -6931,7 +6967,8 @@ public:
SourceLocation DeclStartLoc, SourceLocation DeclLoc,
const CXXScopeSpec &SS, TemplateIdAnnotation *TemplateId,
ArrayRef<TemplateParameterList *> ParamLists,
- bool IsFriend, bool &IsMemberSpecialization, bool &Invalid);
+ bool IsFriend, bool &IsMemberSpecialization, bool &Invalid,
+ bool SuppressDiagnostic = false);
DeclResult CheckClassTemplate(
Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc,
@@ -7843,10 +7880,12 @@ public:
DeduceAutoResult
DeduceAutoType(TypeSourceInfo *AutoType, Expr *&Initializer, QualType &Result,
- Optional<unsigned> DependentDeductionDepth = None);
+ Optional<unsigned> DependentDeductionDepth = None,
+ bool IgnoreConstraints = false);
DeduceAutoResult
DeduceAutoType(TypeLoc AutoTypeLoc, Expr *&Initializer, QualType &Result,
- Optional<unsigned> DependentDeductionDepth = None);
+ Optional<unsigned> DependentDeductionDepth = None,
+ bool IgnoreConstraints = false);
void DiagnoseAutoDeductionFailure(VarDecl *VDecl, Expr *Init);
bool DeduceReturnType(FunctionDecl *FD, SourceLocation Loc,
bool Diagnose = true);
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index a51429264db..6d1db38e36c 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -716,6 +716,61 @@ ASTContext::CanonicalTemplateTemplateParm::Profile(llvm::FoldingSetNodeID &ID,
RequiresClause->Profile(ID, C, /*Canonical=*/true);
}
+static Expr *
+canonicalizeImmediatelyDeclaredConstraint(const ASTContext &C, Expr *IDC,
+ QualType ConstrainedType) {
+ // This is a bit ugly - we need to form a new immediately-declared
+ // constraint that references the new parameter; this would ideally
+ // require semantic analysis (e.g. template<C T> struct S {}; - the
+ // converted arguments of C<T> could be an argument pack if C is
+ // declared as template<typename... T> concept C = ...).
+ // We don't have semantic analysis here so we dig deep into the
+ // ready-made constraint expr and change the thing manually.
+ ConceptSpecializationExpr *CSE;
+ if (const auto *Fold = dyn_cast<CXXFoldExpr>(IDC))
+ CSE = cast<ConceptSpecializationExpr>(Fold->getLHS());
+ else
+ CSE = cast<ConceptSpecializationExpr>(IDC);
+ ArrayRef<TemplateArgument> OldConverted = CSE->getTemplateArguments();
+ SmallVector<TemplateArgument, 3> NewConverted;
+ NewConverted.reserve(OldConverted.size());
+ if (OldConverted.front().getKind() == TemplateArgument::Pack) {
+ // The case:
+ // template<typename... T> concept C = true;
+ // template<C<int> T> struct S; -> constraint is C<{T, int}>
+ NewConverted.push_back(ConstrainedType);
+ for (auto &Arg : OldConverted.front().pack_elements().drop_front(1))
+ NewConverted.push_back(Arg);
+ TemplateArgument NewPack(NewConverted);
+
+ NewConverted.clear();
+ NewConverted.push_back(NewPack);
+ assert(OldConverted.size() == 1 &&
+ "Template parameter pack should be the last parameter");
+ } else {
+ assert(OldConverted.front().getKind() == TemplateArgument::Type &&
+ "Unexpected first argument kind for immediately-declared "
+ "constraint");
+ NewConverted.push_back(ConstrainedType);
+ for (auto &Arg : OldConverted.drop_front(1))
+ NewConverted.push_back(Arg);
+ }
+ Expr *NewIDC = ConceptSpecializationExpr::Create(
+ C, NestedNameSpecifierLoc(), /*TemplateKWLoc=*/SourceLocation(),
+ CSE->getConceptNameInfo(), /*FoundDecl=*/CSE->getNamedConcept(),
+ CSE->getNamedConcept(),
+ // Actually canonicalizing a TemplateArgumentLoc is difficult so we
+ // simply omit the ArgsAsWritten
+ /*ArgsAsWritten=*/nullptr, NewConverted, nullptr);
+
+ if (auto *OrigFold = dyn_cast<CXXFoldExpr>(IDC))
+ NewIDC = new (C) CXXFoldExpr(OrigFold->getType(), SourceLocation(), NewIDC,
+ BinaryOperatorKind::BO_LAnd,
+ SourceLocation(), /*RHS=*/nullptr,
+ SourceLocation(), /*NumExpansions=*/None);
+ return NewIDC;
+}
+
TemplateTemplateParmDecl *
ASTContext::getCanonicalTemplateTemplateParmDecl(
TemplateTemplateParmDecl *TTP) const {
@@ -743,68 +798,23 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(
TTP->isExpandedParameterPack() ?
llvm::Optional<unsigned>(TTP->getNumExpansionParameters()) : None);
if (const auto *TC = TTP->getTypeConstraint()) {
- // This is a bit ugly - we need to form a new immediately-declared
- // constraint that references the new parameter; this would ideally
- // require semantic analysis (e.g. template<C T> struct S {}; - the
- // converted arguments of C<T> could be an argument pack if C is
- // declared as template<typename... T> concept C = ...).
- // We don't have semantic analysis here so we dig deep into the
- // ready-made constraint expr and change the thing manually.
- Expr *IDC = TC->getImmediatelyDeclaredConstraint();
- ConceptSpecializationExpr *CSE;
- if (const auto *Fold = dyn_cast<CXXFoldExpr>(IDC))
- CSE = cast<ConceptSpecializationExpr>(Fold->getLHS());
- else
- CSE = cast<ConceptSpecializationExpr>(IDC);
- ArrayRef<TemplateArgument> OldConverted = CSE->getTemplateArguments();
- SmallVector<TemplateArgument, 3> NewConverted;
- NewConverted.reserve(OldConverted.size());
-
QualType ParamAsArgument(NewTTP->getTypeForDecl(), 0);
- if (OldConverted.front().getKind() == TemplateArgument::Pack) {
- // The case:
- // template<typename... T> concept C = true;
- // template<C<int> T> struct S; -> constraint is C<{T, int}>
- NewConverted.push_back(ParamAsArgument);
- for (auto &Arg : OldConverted.front().pack_elements().drop_front(1))
- NewConverted.push_back(Arg);
- TemplateArgument NewPack(NewConverted);
-
- NewConverted.clear();
- NewConverted.push_back(NewPack);
- assert(OldConverted.size() == 1 &&
- "Template parameter pack should be the last parameter");
- } else {
- assert(OldConverted.front().getKind() == TemplateArgument::Type &&
- "Unexpected first argument kind for immediately-declared "
- "constraint");
- NewConverted.push_back(ParamAsArgument);
- for (auto &Arg : OldConverted.drop_front(1))
- NewConverted.push_back(Arg);
- }
- Expr *NewIDC = ConceptSpecializationExpr::Create(*this,
- NestedNameSpecifierLoc(), /*TemplateKWLoc=*/SourceLocation(),
- CSE->getConceptNameInfo(), /*FoundDecl=*/CSE->getNamedConcept(),
- CSE->getNamedConcept(),
- // Actually canonicalizing a TemplateArgumentLoc is difficult so we
- // simply omit the ArgsAsWritten
- /*ArgsAsWritten=*/nullptr, NewConverted, nullptr);
-
- if (auto *OrigFold = dyn_cast<CXXFoldExpr>(IDC))
- NewIDC = new (*this) CXXFoldExpr(OrigFold->getType(),
- SourceLocation(), NewIDC,
- BinaryOperatorKind::BO_LAnd,
- SourceLocation(), /*RHS=*/nullptr,
- SourceLocation(),
- /*NumExpansions=*/None);
-
+ Expr *NewIDC = canonicalizeImmediatelyDeclaredConstraint(
+ *this, TC->getImmediatelyDeclaredConstraint(),
+ ParamAsArgument);
+ TemplateArgumentListInfo CanonArgsAsWritten;
+ if (auto *Args = TC->getTemplateArgsAsWritten())
+ for (const auto &ArgLoc : Args->arguments())
+ CanonArgsAsWritten.addArgument(
+ TemplateArgumentLoc(ArgLoc.getArgument(),
+ TemplateArgumentLocInfo()));
NewTTP->setTypeConstraint(
NestedNameSpecifierLoc(),
DeclarationNameInfo(TC->getNamedConcept()->getDeclName(),
SourceLocation()), /*FoundDecl=*/nullptr,
// Actually canonicalizing a TemplateArgumentLoc is difficult so we
// simply omit the ArgsAsWritten
- CSE->getNamedConcept(), /*ArgsAsWritten=*/nullptr, NewIDC);
+ TC->getNamedConcept(), /*ArgsAsWritten=*/nullptr, NewIDC);
}
CanonParams.push_back(NewTTP);
} else if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P)) {
@@ -839,6 +849,13 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(
NTTP->isParameterPack(),
TInfo);
}
+ if (AutoType *AT = T->getContainedAutoType()) {
+ if (AT->isConstrained()) {
+ Param->setPlaceholderTypeConstraint(
+ canonicalizeImmediatelyDeclaredConstraint(
+ *this, NTTP->getPlaceholderTypeConstraint(), T));
+ }
+ }
CanonParams.push_back(Param);
} else
@@ -943,7 +960,7 @@ ASTContext::ASTContext(LangOptions &LOpts, SourceManager &SM,
Builtin::Context &builtins)
: ConstantArrayTypes(this_()), FunctionProtoTypes(this_()),
TemplateSpecializationTypes(this_()),
- DependentTemplateSpecializationTypes(this_()),
+ DependentTemplateSpecializationTypes(this_()), AutoTypes(this_()),
SubstTemplateTemplateParmPacks(this_()),
CanonTemplateTemplateParms(this_()), SourceMgr(SM), LangOpts(LOpts),
SanitizerBL(new SanitizerBlacklist(LangOpts.SanitizerBlacklistFiles, SM)),
@@ -5124,21 +5141,29 @@ QualType ASTContext::getUnaryTransformType(QualType BaseType,
/// getAutoType - Return the uniqued reference to the 'auto' type which has been
/// deduced to the given type, or to the canonical undeduced 'auto' type, or the
/// canonical deduced-but-dependent 'auto' type.
-QualType ASTContext::getAutoType(QualType DeducedType, AutoTypeKeyword Keyword,
- bool IsDependent, bool IsPack) const {
+QualType
+ASTContext::getAutoType(QualType DeducedType, AutoTypeKeyword Keyword,
+ bool IsDependent, bool IsPack,
+ ConceptDecl *TypeConstraintConcept,
+ ArrayRef<TemplateArgument> TypeConstraintArgs) const {
assert((!IsPack || IsDependent) && "only use IsPack for a dependent pack");
- if (DeducedType.isNull() && Keyword == AutoTypeKeyword::Auto && !IsDependent)
+ if (DeducedType.isNull() && Keyword == AutoTypeKeyword::Auto &&
+ !TypeConstraintConcept && !IsDependent)
return getAutoDeductType();
// Look in the folding set for an existing type.
void *InsertPos = nullptr;
llvm::FoldingSetNodeID ID;
- AutoType::Profile(ID, DeducedType, Keyword, IsDependent, IsPack);
+ AutoType::Profile(ID, *this, DeducedType, Keyword, IsDependent,
+ TypeConstraintConcept, TypeConstraintArgs);
if (AutoType *AT = AutoTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(AT, 0);
- auto *AT = new (*this, TypeAlignment)
- AutoType(DeducedType, Keyword, IsDependent, IsPack);
+ void *Mem = Allocate(sizeof(AutoType) +
+ sizeof(TemplateArgument) * TypeConstraintArgs.size(),
+ TypeAlignment);
+ auto *AT = new (Mem) AutoType(DeducedType, Keyword, IsDependent, IsPack,
+ TypeConstraintConcept, TypeConstraintArgs);
Types.push_back(AT);
if (InsertPos)
AutoTypes.InsertNode(AT, InsertPos);
@@ -5200,7 +5225,8 @@ QualType ASTContext::getAutoDeductType() const {
if (AutoDeductTy.isNull())
AutoDeductTy = QualType(
new (*this, TypeAlignment) AutoType(QualType(), AutoTypeKeyword::Auto,
- /*dependent*/false, /*pack*/false),
+ /*dependent*/false, /*pack*/false,
+ /*concept*/nullptr, /*args*/{}),
0);
return AutoDeductTy;
}
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 22fb67478c9..1f2ce30398c 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -1366,9 +1366,21 @@ ExpectedType ASTNodeImporter::VisitAutoType(const AutoType *T) {
if (!ToDeducedTypeOrErr)
return ToDeducedTypeOrErr.takeError();
- return Importer.getToContext().getAutoType(*ToDeducedTypeOrErr,
- T->getKeyword(),
- /*IsDependent*/false);
+ ExpectedDecl ToTypeConstraintConcept = import(T->getTypeConstraintConcept());
+ if (!ToTypeConstraintConcept)
+ return ToTypeConstraintConcept.takeError();
+
+ SmallVector<TemplateArgument, 2> ToTemplateArgs;
+ ArrayRef<TemplateArgument> FromTemplateArgs = T->getTypeConstraintArguments();
+ if (Error Err = ImportTemplateArguments(FromTemplateArgs.data(),
+ FromTemplateArgs.size(),
+ ToTemplateArgs))
+ return std::move(Err);
+
+ return Importer.getToContext().getAutoType(
+ *ToDeducedTypeOrErr, T->getKeyword(), /*IsDependent*/false,
+ /*IsPack=*/false, cast_or_null<ConceptDecl>(*ToTypeConstraintConcept),
+ ToTemplateArgs);
}
ExpectedType ASTNodeImporter::VisitInjectedClassNameType(
diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp
index db48405055c..91a2f3a8391 100644
--- a/clang/lib/AST/ASTStructuralEquivalence.cpp
+++ b/clang/lib/AST/ASTStructuralEquivalence.cpp
@@ -729,11 +729,31 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
return false;
break;
- case Type::Auto:
- if (!IsStructurallyEquivalent(Context, cast<AutoType>(T1)->getDeducedType(),
- cast<AutoType>(T2)->getDeducedType()))
+ case Type::Auto: {
+ auto *Auto1 = cast<AutoType>(T1);
+ auto *Auto2 = cast<AutoType>(T2);
+ if (!IsStructurallyEquivalent(Context, Auto1->getDeducedType(),
+ Auto2->getDeducedType()))
return false;
+ if (Auto1->isConstrained() != Auto2->isConstrained())
+ return false;
+ if (Auto1->isConstrained()) {
+ if (Auto1->getTypeConstraintConcept() !=
+ Auto2->getTypeConstraintConcept())
+ return false;
+ ArrayRef<TemplateArgument> Auto1Args =
+ Auto1->getTypeConstraintArguments();
+ ArrayRef<TemplateArgument> Auto2Args =
+ Auto2->getTypeConstraintArguments();
+ if (Auto1Args.size() != Auto2Args.size())
+ return false;
+ for (unsigned I = 0, N = Auto1Args.size(); I != N; ++I) {
+ if (!IsStructurallyEquivalent(Context, Auto1Args[I], Auto2Args[I]))
+ return false;
+ }
+ }
break;
+ }
case Type::DeducedTemplateSpecialization: {
const auto *DT1 = cast<DeducedTemplateSpecializationType>(T1);
diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp
index 58ce49aab40..9bd3b64feb4 100755
--- a/clang/lib/AST/DeclTemplate.cpp
+++ b/clang/lib/AST/DeclTemplate.cpp
@@ -164,10 +164,15 @@ static void AdoptTemplateParameterList(TemplateParameterList *Params,
void TemplateParameterList::
getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const {
if (HasConstrainedParameters)
- for (const NamedDecl *Param : *this)
- if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param))
+ for (const NamedDecl *Param : *this) {
+ if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) {
if (const auto *TC = TTP->getTypeConstraint())
AC.push_back(TC->getImmediatelyDeclaredConstraint());
+ } else if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
+ if (const Expr *E = NTTP->getPlaceholderTypeConstraint())
+ AC.push_back(E);
+ }
+ }
if (HasRequiresClause)
AC.push_back(getRequiresClause());
}
@@ -687,8 +692,14 @@ NonTypeTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC,
unsigned D, unsigned P, IdentifierInfo *Id,
QualType T, bool ParameterPack,
TypeSourceInfo *TInfo) {
- return new (C, DC) NonTypeTemplateParmDecl(DC, StartLoc, IdLoc, D, P, Id,
- T, ParameterPack, TInfo);
+ AutoType *AT =
+ C.getLangOpts().ConceptsTS ? T->getContainedAutoType() : nullptr;
+ return new (C, DC,
+ additionalSizeToAlloc<std::pair<QualType, TypeSourceInfo *>,
+ Expr *>(0,
+ AT && AT->isConstrained() ? 1 : 0))
+ NonTypeTemplateParmDecl(DC, StartLoc, IdLoc, D, P, Id, T, ParameterPack,
+ TInfo);
}
NonTypeTemplateParmDecl *NonTypeTemplateParmDecl::Create(
@@ -696,26 +707,34 @@ NonTypeTemplateParmDecl *NonTypeTemplateParmDecl::Create(
SourceLocation IdLoc, unsigned D, unsigned P, IdentifierInfo *Id,
QualType T, TypeSourceInfo *TInfo, ArrayRef<QualType> ExpandedTypes,
ArrayRef<TypeSourceInfo *> ExpandedTInfos) {
+ AutoType *AT = TInfo->getType()->getContainedAutoType();
return new (C, DC,
- additionalSizeToAlloc<std::pair<QualType, TypeSourceInfo *>>(
- ExpandedTypes.size()))
+ additionalSizeToAlloc<std::pair<QualType, TypeSourceInfo *>,
+ Expr *>(
+ ExpandedTypes.size(), AT && AT->isConstrained() ? 1 : 0))
NonTypeTemplateParmDecl(DC, StartLoc, IdLoc, D, P, Id, T, TInfo,
ExpandedTypes, ExpandedTInfos);
}
NonTypeTemplateParmDecl *
-NonTypeTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
- return new (C, ID) NonTypeTemplateParmDecl(nullptr, SourceLocation(),
- SourceLocation(), 0, 0, nullptr,
- QualType(), false, nullptr);
+NonTypeTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID,
+ bool HasTypeConstraint) {
+ return new (C, ID, additionalSizeToAlloc<std::pair<QualType,
+ TypeSourceInfo *>,
+ Expr *>(0,
+ HasTypeConstraint ? 1 : 0))
+ NonTypeTemplateParmDecl(nullptr, SourceLocation(), SourceLocation(),
+ 0, 0, nullptr, QualType(), false, nullptr);
}
NonTypeTemplateParmDecl *
NonTypeTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID,
- unsigned NumExpandedTypes) {
+ unsigned NumExpandedTypes,
+ bool HasTypeConstraint) {
auto *NTTP =
- new (C, ID, additionalSizeToAlloc<std::pair<QualType, TypeSourceInfo *>>(
- NumExpandedTypes))
+ new (C, ID, additionalSizeToAlloc<std::pair<QualType, TypeSourceInfo *>,
+ Expr *>(
+ NumExpandedTypes, HasTypeConstraint ? 1 : 0))
NonTypeTemplateParmDecl(nullptr, SourceLocation(), SourceLocation(),
0, 0, nullptr, QualType(), nullptr, None,
None);
diff --git a/clang/lib/AST/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp
index 27fdca1c4b9..1f9ff9e407d 100644
--- a/clang/lib/AST/ODRHash.cpp
+++ b/clang/lib/AST/ODRHash.cpp
@@ -857,6 +857,13 @@ public:
void VisitAutoType(const AutoType *T) {
ID.AddInteger((unsigned)T->getKeyword());
+ ID.AddInteger(T->isConstrained());
+ if (T->isConstrained()) {
+ AddDecl(T->getTypeConstraintConcept());
+ ID.AddInteger(T->getNumArgs());
+ for (const auto &TA : T->getTypeConstraintArguments())
+ Hash.AddTemplateArgument(TA);
+ }
VisitDeducedType(T);
}
diff --git a/clang/lib/AST/TemplateBase.cpp b/clang/lib/AST/TemplateBase.cpp
index db16c2a06b6..6f0ebf232e7 100644
--- a/clang/lib/AST/TemplateBase.cpp
+++ b/clang/lib/AST/TemplateBase.cpp
@@ -561,7 +561,7 @@ const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
}
const ASTTemplateArgumentListInfo *
-ASTTemplateArgumentListInfo::Create(ASTContext &C,
+ASTTemplateArgumentListInfo::Create(const ASTContext &C,
const TemplateArgumentListInfo &List) {
std::size_t size = totalSizeToAlloc<TemplateArgumentLoc>(List.size());
void *Mem = C.Allocate(size, alignof(ASTTemplateArgumentListInfo));
diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp
index 965ad17fcfa..c9b571862c1 100644
--- a/clang/lib/AST/TextNodeDumper.cpp
+++ b/clang/lib/AST/TextNodeDumper.cpp
@@ -1201,6 +1201,11 @@ void TextNodeDumper::VisitAutoType(const AutoType *T) {
OS << " decltype(auto)";
if (!T->isDeduced())
OS << " undeduced";
+ if (T->isConstrained()) {
+ dumpDeclRef(T->getTypeConstraintConcept());
+ for (const auto &Arg : T->getTypeConstraintArguments())
+ VisitTemplateArgument(Arg);
+ }
}
void TextNodeDumper::VisitTemplateSpecializationType(
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index c5ad711d872..5099494da5f 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -1114,7 +1114,9 @@ public:
return QualType(T, 0);
return Ctx.getAutoType(deducedType, T->getKeyword(),
- T->isDependentType());
+ T->isDependentType(), /*IsPack=*/false,
+ T->getTypeConstraintConcept(),
+ T->getTypeConstraintArguments());
}
// FIXME: Non-trivial to implement, but important for C++
@@ -4158,3 +4160,35 @@ void clang::FixedPointValueToString(SmallVectorImpl<char> &Str,
/*HasUnsignedPadding=*/false);
APFixedPoint(Val, FXSema).toString(Str);
}
+
+AutoType::AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword,
+ bool IsDeducedAsDependent, bool IsDeducedAsPack,
+ ConceptDecl *TypeConstraintConcept,
+ ArrayRef<TemplateArgument> TypeConstraintArgs)
+ : DeducedType(Auto, DeducedAsType, IsDeducedAsDependent,
+ IsDeducedAsDependent, IsDeducedAsPack) {
+ AutoTypeBits.Keyword = (unsigned)Keyword;
+ AutoTypeBits.NumArgs = TypeConstraintArgs.size();
+ this->TypeConstraintConcept = TypeConstraintConcept;
+ if (TypeConstraintConcept) {
+ TemplateArgument *ArgBuffer = getArgBuffer();
+ for (const TemplateArgument &Arg : TypeConstraintArgs) {
+ if (Arg.containsUnexpandedParameterPack())
+ setContainsUnexpandedParameterPack();
+
+ new (ArgBuffer++) TemplateArgument(Arg);
+ }
+ }
+}
+
+void AutoType::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
+ QualType Deduced, AutoTypeKeyword Keyword,
+ bool IsDependent, ConceptDecl *CD,
+ ArrayRef<TemplateArgument> Arguments) {
+ ID.AddPointer(Deduced.getAsOpaquePtr());
+ ID.AddInteger((unsigned)Keyword);
+ ID.AddBoolean(IsDependent);
+ ID.AddPointer(CD);
+ for (const TemplateArgument &Arg : Arguments)
+ Arg.Profile(ID, Context);
+}
diff --git a/clang/lib/AST/TypeLoc.cpp b/clang/lib/AST/TypeLoc.cpp
index 6e67ca8e0af..665a86f2c14 100644
--- a/clang/lib/AST/TypeLoc.cpp
+++ b/clang/lib/AST/TypeLoc.cpp
@@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/TypeLoc.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Attr.h"
#include "clang/AST/Expr.h"
@@ -589,3 +590,97 @@ void TemplateSpecializationTypeLoc::initializeArgLocs(ASTContext &Context,
}
}
}
+
+DeclarationNameInfo AutoTypeLoc::getConceptNameInfo() const {
+ return DeclarationNameInfo(getNamedConcept()->getDeclName(),
+ getLocalData()->ConceptNameLoc);
+}
+
+void AutoTypeLoc::initializeLocal(ASTContext &Context, SourceLocation Loc) {
+ setNestedNameSpecifierLoc(NestedNameSpecifierLoc());
+ setTemplateKWLoc(Loc);
+ setConceptNameLoc(Loc);
+ setFoundDecl(nullptr);
+ setRAngleLoc(Loc);
+ setLAngleLoc(Loc);
+ TemplateSpecializationTypeLoc::initializeArgLocs(Context, getNumArgs(),
+ getTypePtr()->getArgs(),
+ getArgInfos(), Loc);
+ setNameLoc(Loc);
+}
+
+
+namespace {
+
+ class GetContainedAutoTypeLocVisitor :
+ public TypeLocVisitor<GetContainedAutoTypeLocVisitor, TypeLoc> {
+ public:
+ using TypeLocVisitor<GetContainedAutoTypeLocVisitor, TypeLoc>::Visit;
+
+ TypeLoc VisitAutoTypeLoc(AutoTypeLoc TL) {
+ return TL;
+ }
+
+ // Only these types can contain the desired 'auto' type.
+
+ TypeLoc VisitElaboratedTypeLoc(ElaboratedTypeLoc T) {
+ return Visit(T.getNamedTypeLoc());
+ }
+
+ TypeLoc VisitQualifiedTypeLoc(QualifiedTypeLoc T) {
+ return Visit(T.getUnqualifiedLoc());
+ }
+
+ TypeLoc VisitPointerTypeLoc(PointerTypeLoc T) {
+ return Visit(T.getPointeeLoc());
+ }
+
+ TypeLoc VisitBlockPointerTypeLoc(BlockPointerTypeLoc T) {
+ return Visit(T.getPointeeLoc());
+ }
+
+ TypeLoc VisitReferenceTypeLoc(ReferenceTypeLoc T) {
+ return Visit(T.getPointeeLoc());
+ }
+
+ TypeLoc VisitMemberPointerTypeLoc(MemberPointerTypeLoc T) {
+ return Visit(T.getPointeeLoc());
+ }
+
+ TypeLoc VisitArrayTypeLoc(ArrayTypeLoc T) {
+ return Visit(T.getElementLoc());
+ }
+
+ TypeLoc VisitFunctionTypeLoc(FunctionTypeLoc T) {
+ return Visit(T.getReturnLoc());
+ }
+
+ TypeLoc VisitParenTypeLoc(ParenTypeLoc T) {
+ return Visit(T.getInnerLoc());
+ }
+
+ TypeLoc VisitAttributedTypeLoc(AttributedTypeLoc T) {
+ return Visit(T.getModifiedLoc());
+ }
+
+ TypeLoc VisitMacroQualifiedTypeLoc(MacroQualifiedTypeLoc T) {
+ return Visit(T.getInnerLoc());
+ }
+
+ TypeLoc VisitAdjustedTypeLoc(AdjustedTypeLoc T) {
+ return Visit(T.getOriginalLoc());
+ }
+
+ TypeLoc VisitPackExpansionTypeLoc(PackExpansionTypeLoc T) {
+ return Visit(T.getPatternLoc());
+ }
+ };
+
+} // namespace
+
+AutoTypeLoc TypeLoc::getContainedAutoTypeLoc() const {
+ TypeLoc Res = GetContainedAutoTypeLocVisitor().Visit(*this);
+ if (Res.isNull())
+ return AutoTypeLoc();
+ return Res.getAs<AutoTypeLoc>();
+}
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index c2f4baec989..4a7e765a2bd 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -1046,6 +1046,13 @@ void TypePrinter::printAutoBefore(const AutoType *T, raw_ostream &OS) {
if (!T->getDeducedType().isNull()) {
printBefore(T->getDeducedType(), OS);
} else {
+ if (T->isConstrained()) {
+ OS << T->getTypeConstraintConcept()->getName();
+ auto Args = T->getTypeConstraintArguments();
+ if (!Args.empty())
+ printTemplateArgumentList(OS, Args, Policy);
+ OS << ' ';
+ }
switch (T->getKeyword()) {
case AutoTypeKeyword::Auto: OS << "auto"; break;
case AutoTypeKeyword::DecltypeAuto: OS << "decltype(auto)"; break;
@@ -1234,20 +1241,18 @@ void TypePrinter::printEnumAfter(const EnumType *T, raw_ostream &OS) {}
void TypePrinter::printTemplateTypeParmBefore(const TemplateTypeParmType *T,
raw_ostream &OS) {
- if (IdentifierInfo *Id = T->getIdentifier())
- OS << Id->getName();
- else {
- bool IsLambdaAutoParam = false;
- if (auto D = T->getDecl()) {
- if (auto M = dyn_cast_or_null<CXXMethodDecl>(D->getDeclContext()))
- IsLambdaAutoParam = D->isImplicit() && M->getParent()->isLambda();
+ TemplateTypeParmDecl *D = T->getDecl();
+ if (D && D->isImplicit()) {
+ if (auto *TC = D->getTypeConstraint()) {
+ TC->print(OS, Policy);
+ OS << ' ';
}
+ OS << "auto";
+ } else if (IdentifierInfo *Id = T->getIdentifier())
+ OS << Id->getName();
+ else
+ OS << "type-parameter-" << T->getDepth() << '-' << T->getIndex();
- if (IsLambdaAutoParam)
- OS << "auto";
- else
- OS << "type-parameter-" << T->getDepth() << '-' << T->getIndex();
- }
spaceBeforePlaceHolder(OS);
}
diff --git a/clang/lib/Parse/ParseCXXInlineMethods.cpp b/clang/lib/Parse/ParseCXXInlineMethods.cpp
index f8b5fec4380..a7596578416 100644
--- a/clang/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/clang/lib/Parse/ParseCXXInlineMethods.cpp
@@ -133,7 +133,9 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(
LexedMethod* LM = new LexedMethod(this, FnD);
getCurrentClass().LateParsedDeclarations.push_back(LM);
- LM->TemplateScope = getCurScope()->isTemplateParamScope();
+ LM->TemplateScope = getCurScope()->isTemplateParamScope() ||
+ (FnD && isa<FunctionTemplateDecl>(FnD) &&
+ cast<FunctionTemplateDecl>(FnD)->isAbbreviated());
CachedTokens &Toks = LM->Toks;
tok::TokenKind kind = Tok.getKind();
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 065a82b9298..4af993c4527 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -2962,6 +2962,7 @@ Parser::DiagnoseMissingSemiAfterTagDefinition(DeclSpec &DS, AccessSpecifier AS,
case Sema::NC_ContextIndependentExpr:
case Sema::NC_VarTemplate:
case Sema::NC_FunctionTemplate:
+ case Sema::NC_Concept:
// Might be a redeclaration of a prior entity.
break;
}
@@ -3193,6 +3194,18 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
continue;
}
+ if (Next.is(tok::annot_template_id) &&
+ static_cast<TemplateIdAnnotation *>(Next.getAnnotationValue())
+ ->Kind == TNK_Concept_template &&
+ GetLookAheadToken(2).isOneOf(tok::kw_auto, tok::kw_decltype)) {
+ DS.getTypeSpecScope() = SS;
+ // This is a qualified placeholder-specifier, e.g., ::C<int> auto ...
+ // Consume the scope annotation and continue to consume the template-id
+ // as a placeholder-specifier.
+ ConsumeAnnotationToken();
+ continue;
+ }
+
if (Next.is(tok::annot_typename)) {
DS.getTypeSpecScope() = SS;
ConsumeAnnotationToken(); // The C++ scope.
@@ -3235,6 +3248,10 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// C++ doesn't have implicit int. Diagnose it as a typo w.r.t. to the
// typename.
if (!TypeRep) {
+ if (TryAnnotateTypeConstraint())
+ goto DoneWithDeclSpec;
+ if (isTypeConstraintAnnotation())
+ continue;
// Eat the scope spec so the identifier is current.
ConsumeAnnotationToken();
ParsedAttributesWithRange Attrs(AttrFactory);
@@ -3384,6 +3401,10 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// 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.
if (!TypeRep) {
+ if (TryAnnotateTypeConstraint())
+ goto DoneWithDeclSpec;
+ if (isTypeConstraintAnnotation())
+ continue;
ParsedAttributesWithRange Attrs(AttrFactory);
if (ParseImplicitInt(DS, nullptr, TemplateInfo, AS, DSContext, Attrs)) {
if (!Attrs.empty()) {
@@ -3433,9 +3454,51 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
continue;
}
- // type-name
+ // type-name or placeholder-specifier
case tok::annot_template_id: {
TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
+ if (TemplateId->Kind == TNK_Concept_template) {
+ if (NextToken().is(tok::identifier)) {
+ Diag(Loc, diag::err_placeholder_expected_auto_or_decltype_auto)
+ << FixItHint::CreateInsertion(NextToken().getLocation(), "auto");
+ // Attempt to continue as if 'auto' was placed here.
+ isInvalid = DS.SetTypeSpecType(TST_auto, Loc, PrevSpec, DiagID,
+ TemplateId, Policy);
+ break;
+ }
+ if (!NextToken().isOneOf(tok::kw_auto, tok::kw_decltype))
+ goto DoneWithDeclSpec;
+ ConsumeAnnotationToken();
+ SourceLocation AutoLoc = Tok.getLocation();
+ if (TryConsumeToken(tok::kw_decltype)) {
+ BalancedDelimiterTracker Tracker(*this, tok::l_paren);
+ if (Tracker.consumeOpen()) {
+ // Something like `void foo(Iterator decltype i)`
+ Diag(Tok, diag::err_expected) << tok::l_paren;
+ } else {
+ if (!TryConsumeToken(tok::kw_auto)) {
+ // Something like `void foo(Iterator decltype(int) i)`
+ Tracker.skipToEnd();
+ Diag(Tok, diag::err_placeholder_expected_auto_or_decltype_auto)
+ << FixItHint::CreateReplacement(SourceRange(AutoLoc,
+ Tok.getLocation()),
+ "auto");
+ } else {
+ Tracker.consumeClose();
+ }
+ }
+ ConsumedEnd = Tok.getLocation();
+ // Even if something went wrong above, continue as if we've seen
+ // `decltype(auto)`.
+ isInvalid = DS.SetTypeSpecType(TST_decltype_auto, Loc, PrevSpec,
+ DiagID, TemplateId, Policy);
+ } else {
+ isInvalid = DS.SetTypeSpecType(TST_auto, Loc, PrevSpec, DiagID,
+ TemplateId, Policy);
+ }
+ break;
+ }
+
if (TemplateId->Kind != TNK_Type_template &&
TemplateId->Kind != TNK_Undeclared_template) {
// This template-id does not refer to a type name, so we're
@@ -6027,11 +6090,12 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
while (1) {
if (Tok.is(tok::l_paren)) {
+ bool IsFunctionDeclaration = D.isFunctionDeclaratorAFunctionDeclaration();
// Enter function-declaration scope, limiting any declarators to the
// function prototype scope, including parameter declarators.
ParseScope PrototypeScope(this,
Scope::FunctionPrototypeScope|Scope::DeclScope|
- (D.isFunctionDeclaratorAFunctionDeclaration()
+ (IsFunctionDeclaration
? Scope::FunctionDeclarationScope : 0));
// The paren may be part of a C++ direct initializer, eg. "int x(1);".
@@ -6050,7 +6114,12 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
ParsedAttributes attrs(AttrFactory);
BalancedDelimiterTracker T(*this, tok::l_paren);
T.consumeOpen();
+ if (IsFunctionDeclaration)
+ Actions.ActOnStartFunctionDeclarationDeclarator(D,
+ TemplateParameterDepth);
ParseFunctionDeclarator(D, attrs, T, IsAmbiguous);
+ if (IsFunctionDeclaration)
+ Actions.ActOnFinishFunctionDeclarationDeclarator(D);
PrototypeScope.Exit();
} else if (Tok.is(tok::l_square)) {
ParseBracketDeclarator(D);
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 9c7d3c56655..f872aa3a950 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -2642,6 +2642,8 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
}
ParsingDeclarator DeclaratorInfo(*this, DS, DeclaratorContext::MemberContext);
+ if (TemplateInfo.TemplateParams)
+ DeclaratorInfo.setTemplateParameterLists(TemplateParams);
VirtSpecifiers VS;
// Hold late-parsed attributes so we can attach a Decl to them later.
diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp
index 2ac8be430c3..e96baec0780 100644
--- a/clang/lib/Parse/ParseTemplate.cpp
+++ b/clang/lib/Parse/ParseTemplate.cpp
@@ -240,6 +240,8 @@ Decl *Parser::ParseSingleDeclarationAfterTemplate(
// Parse the declarator.
ParsingDeclarator DeclaratorInfo(*this, DS, (DeclaratorContext)Context);
+ if (TemplateInfo.TemplateParams)
+ DeclaratorInfo.setTemplateParameterLists(*TemplateInfo.TemplateParams);
ParseDeclarator(DeclaratorInfo);
// Error parsing the declarator?
if (!DeclaratorInfo.hasName()) {
@@ -601,6 +603,7 @@ Parser::TPResult Parser::isStartOfTemplateTypeParameter() {
/// typename
///
NamedDecl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) {
+
switch (isStartOfTemplateTypeParameter()) {
case TPResult::True:
// Is there just a typo in the input code? ('typedef' instead of
@@ -618,7 +621,6 @@ NamedDecl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) {
}
return ParseTypeParameter(Depth, Position);
-
case TPResult::False:
break;
@@ -678,7 +680,6 @@ bool Parser::isTypeConstraintAnnotation() {
bool Parser::TryAnnotateTypeConstraint() {
if (!getLangOpts().ConceptsTS)
return false;
-
CXXScopeSpec SS;
bool WasScopeAnnotation = Tok.is(tok::annot_cxxscope);
if (ParseOptionalCXXScopeSpecifier(
diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp
index 79e96816f86..ad0a15b0c8a 100644
--- a/clang/lib/Parse/ParseTentative.cpp
+++ b/clang/lib/Parse/ParseTentative.cpp
@@ -1313,6 +1313,18 @@ public:
Parser::TPResult
Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
bool *InvalidAsDeclSpec) {
+ auto IsPlaceholderSpecifier = [&] (TemplateIdAnnotation *TemplateId,
+ int Lookahead) {
+ // We have a placeholder-constraint (we check for 'auto' or 'decltype' to
+ // distinguish 'C<int>;' from 'C<int> auto c = 1;')
+ return TemplateId->Kind == TNK_Concept_template &&
+ GetLookAheadToken(Lookahead + 1).isOneOf(tok::kw_auto, tok::kw_decltype,
+ // If we have an identifier here, the user probably forgot the
+ // 'auto' in the placeholder constraint, e.g. 'C<int> x = 2;'
+ // This will be diagnosed nicely later, so disambiguate as a
+ // declaration.
+ tok::identifier);
+ };
switch (Tok.getKind()) {
case tok::identifier: {
// Check for need to substitute AltiVec __vector keyword
@@ -1516,6 +1528,8 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
*InvalidAsDeclSpec = NextToken().is(tok::l_paren);
return TPResult::Ambiguous;
}
+ if (IsPlaceholderSpecifier(TemplateId, /*Lookahead=*/0))
+ return TPResult::True;
if (TemplateId->Kind != TNK_Type_template)
return TPResult::False;
CXXScopeSpec SS;
@@ -1529,6 +1543,13 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
if (TryAnnotateTypeOrScopeToken())
return TPResult::Error;
if (!Tok.is(tok::annot_typename)) {
+ if (Tok.is(tok::annot_cxxscope) &&
+ NextToken().is(tok::annot_template_id)) {
+ TemplateIdAnnotation *TemplateId =
+ takeTemplateIdAnnotation(NextToken());
+ if (IsPlaceholderSpecifier(TemplateId, /*Lookahead=*/1))
+ return TPResult::True;
+ }
// If the next token is an identifier or a type qualifier, then this
// can't possibly be a valid expression either.
if (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::identifier)) {
diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index 0194c243f93..0b778bd2427 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -1136,6 +1136,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
// Poison SEH identifiers so they are flagged as illegal in function bodies.
PoisonSEHIdentifiersRAIIObject PoisonSEHIdentifiers(*this, true);
const DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo();
+ TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth);
// If this is C90 and the declspecs were completely missing, fudge in an
// implicit int. We do this here because this is the only place where
@@ -1262,6 +1263,15 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
// safe because we're always the sole owner.
D.getMutableDeclSpec().abort();
+ // With abbreviated function templates - we need to explicitly add depth to
+ // account for the implicit template parameter list induced by the template.
+ if (auto *Template = dyn_cast_or_null<FunctionTemplateDecl>(Res))
+ if (Template->isAbbreviated() &&
+ Template->getTemplateParameters()->getParam(0)->isImplicit())
+ // First template parameter is implicit - meaning no explicit template
+ // parameter list was specified.
+ CurTemplateDepthTracker.addDepth(1);
+
if (TryConsumeToken(tok::equal)) {
assert(getLangOpts().CPlusPlus && "Only C++ function definitions have '='");
@@ -1732,6 +1742,20 @@ Parser::TryAnnotateName(CorrectionCandidateCallback *CCC) {
return ANK_Error;
return ANK_Success;
}
+ case Sema::NC_Concept: {
+ UnqualifiedId Id;
+ Id.setIdentifier(Name, NameLoc);
+ if (Next.is(tok::less))
+ // We have a concept name followed by '<'. Consume the identifier token so
+ // we reach the '<' and annotate it.
+ ConsumeToken();
+ if (AnnotateTemplateIdToken(
+ TemplateTy::make(Classification.getTemplateName()),
+ Classification.getTemplateNameKind(), SS, SourceLocation(), Id,
+ /*AllowTypeAnnotation=*/false, /*TypeConstraint=*/true))
+ return ANK_Error;
+ return ANK_Success;
+ }
}
// Unable to classify the name, but maybe we can annotate a scope specifier.
diff --git a/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp
index 639231c8723..94d87974624 100644
--- a/clang/lib/Sema/DeclSpec.cpp
+++ b/clang/lib/Sema/DeclSpec.cpp
@@ -784,6 +784,15 @@ bool DeclSpec::SetTypeSpecType(TST T, SourceLocation TagKwLoc,
return false;
}
+bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec,
+ unsigned &DiagID, TemplateIdAnnotation *Rep,
+ const PrintingPolicy &Policy) {
+ assert(T == TST_auto || T == TST_decltype_auto);
+ ConstrainedAuto = true;
+ TemplateIdRep = Rep;
+ return SetTypeSpecType(T, Loc, PrevSpec, DiagID, Policy);
+}
+
bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc,
const char *&PrevSpec,
unsigned &DiagID,
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 7eb8c8d2f76..9cfce5a63b1 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -52,6 +52,21 @@ SourceLocation Sema::getLocForEndOfToken(SourceLocation Loc, unsigned Offset) {
ModuleLoader &Sema::getModuleLoader() const { return PP.getModuleLoader(); }
+IdentifierInfo *
+Sema::InventAbbreviatedTemplateParameterTypeName(IdentifierInfo *ParamName,
+ unsigned int Index) {
+ std::string InventedName;
+ llvm::raw_string_ostream OS(InventedName);
+
+ if (!ParamName)
+ OS << "auto:" << Index + 1;
+ else
+ OS << ParamName->getName() << ":auto";
+
+ OS.flush();
+ return &Context.Idents.get(OS.str());
+}
+
PrintingPolicy Sema::getPrintingPolicy(const ASTContext &Context,
const Preprocessor &PP) {
PrintingPolicy Policy = Context.getPrintingPolicy();
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 372f3d15859..0bf49033653 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -10,6 +10,7 @@
//
//===----------------------------------------------------------------------===//
+#include "TreeTransform.h"
#include "TypeLocBuilder.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
@@ -1153,6 +1154,10 @@ Corrected:
return ParsedType::make(T);
}
+ if (isa<ConceptDecl>(FirstDecl))
+ return NameClassification::Concept(
+ TemplateName(cast<TemplateDecl>(FirstDecl)));
+
// We can have a type template here if we're classifying a template argument.
if (isa<TemplateDecl>(FirstDecl) && !isa<FunctionTemplateDecl>(FirstDecl) &&
!isa<VarTemplateDecl>(FirstDecl))
@@ -8656,11 +8661,21 @@ static Scope *getTagInjectionScope(Scope *S, const LangOptions &LangOpts) {
NamedDecl*
Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
TypeSourceInfo *TInfo, LookupResult &Previous,
- MultiTemplateParamsArg TemplateParamLists,
+ MultiTemplateParamsArg TemplateParamListsRef,
bool &AddToScope) {
QualType R = TInfo->getType();
assert(R->isFunctionType());
+ SmallVector<TemplateParameterList *, 4> TemplateParamLists;
+ for (TemplateParameterList *TPL : TemplateParamListsRef)
+ TemplateParamLists.push_back(TPL);
+ if (TemplateParameterList *Invented = D.getInventedTemplateParameterList()) {
+ if (!TemplateParamLists.empty() &&
+ Invented->getDepth() == TemplateParamLists.back()->getDepth())
+ TemplateParamLists.back() = Invented;
+ else
+ TemplateParamLists.push_back(Invented);
+ }
// TODO: consider using NameInfo for diagnostic.
DeclarationNameInfo NameInfo = GetNameForDeclarator(D);
@@ -8740,15 +8755,16 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// Match up the template parameter lists with the scope specifier, then
// determine whether we have a template or a template specialization.
bool Invalid = false;
- if (TemplateParameterList *TemplateParams =
- MatchTemplateParametersToScopeSpecifier(
- D.getDeclSpec().getBeginLoc(), D.getIdentifierLoc(),
- D.getCXXScopeSpec(),
- D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId
- ? D.getName().TemplateId
- : nullptr,
- TemplateParamLists, isFriend, isMemberSpecialization,
- Invalid)) {
+ TemplateParameterList *TemplateParams =
+ MatchTemplateParametersToScopeSpecifier(
+ D.getDeclSpec().getBeginLoc(), D.getIdentifierLoc(),
+ D.getCXXScopeSpec(),
+ D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId
+ ? D.getName().TemplateId
+ : nullptr,
+ TemplateParamLists, isFriend, isMemberSpecialization,
+ Invalid);
+ if (TemplateParams) {
if (TemplateParams->size() > 0) {
// This is a function template
@@ -8781,7 +8797,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// For source fidelity, store the other template param lists.
if (TemplateParamLists.size() > 1) {
NewFD->setTemplateParameterListsInfo(Context,
- TemplateParamLists.drop_back(1));
+ ArrayRef<TemplateParameterList *>(TemplateParamLists)
+ .drop_back(1));
}
} else {
// This is a function template specialization.
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 9916d3be77e..9fa5691983a 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -17386,3 +17386,50 @@ MSPropertyDecl *Sema::HandleMSProperty(Scope *S, RecordDecl *Record,
return NewPD;
}
+
+void Sema::ActOnStartFunctionDeclarationDeclarator(
+ Declarator &Declarator, unsigned TemplateParameterDepth) {
+ auto &Info = InventedParameterInfos.emplace_back();
+ TemplateParameterList *ExplicitParams = nullptr;
+ ArrayRef<TemplateParameterList *> ExplicitLists =
+ Declarator.getTemplateParameterLists();
+ if (!ExplicitLists.empty()) {
+ bool IsMemberSpecialization, IsInvalid;
+ ExplicitParams = MatchTemplateParametersToScopeSpecifier(
+ Declarator.getBeginLoc(), Declarator.getIdentifierLoc(),
+ Declarator.getCXXScopeSpec(), /*TemplateId=*/nullptr,
+ ExplicitLists, /*IsFriend=*/false, IsMemberSpecialization, IsInvalid,
+ /*SuppressDiagnostic=*/true);
+ }
+ if (ExplicitParams) {
+ Info.AutoTemplateParameterDepth = ExplicitParams->getDepth();
+ for (NamedDecl *Param : *ExplicitParams)
+ Info.TemplateParams.push_back(Param);
+ Info.NumExplicitTemplateParams = ExplicitParams->size();
+ } else {
+ Info.AutoTemplateParameterDepth = TemplateParameterDepth;
+ Info.NumExplicitTemplateParams = 0;
+ }
+}
+
+void Sema::ActOnFinishFunctionDeclarationDeclarator(Declarator &Declarator) {
+ auto &FSI = InventedParameterInfos.back();
+ if (FSI.TemplateParams.size() > FSI.NumExplicitTemplateParams) {
+ if (FSI.NumExplicitTemplateParams != 0) {
+ TemplateParameterList *ExplicitParams =
+ Declarator.getTemplateParameterLists().back();
+ Declarator.setInventedTemplateParameterList(
+ TemplateParameterList::Create(
+ Context, ExplicitParams->getTemplateLoc(),
+ ExplicitParams->getLAngleLoc(), FSI.TemplateParams,
+ ExplicitParams->getRAngleLoc(),
+ ExplicitParams->getRequiresClause()));
+ } else {
+ Declarator.setInventedTemplateParameterList(
+ TemplateParameterList::Create(
+ Context, SourceLocation(), SourceLocation(), FSI.TemplateParams,
+ SourceLocation(), /*RequiresClause=*/nullptr));
+ }
+ }
+ InventedParameterInfos.pop_back();
+}
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index c2d14a44f53..ae89b146c40 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -791,7 +791,8 @@ QualType Sema::buildLambdaInitCaptureInitialization(
// deduce against.
QualType DeductType = Context.getAutoDeductType();
TypeLocBuilder TLB;
- TLB.pushTypeSpec(DeductType).setNameLoc(Loc);
+ AutoTypeLoc TL = TLB.push<AutoTypeLoc>(DeductType);
+ TL.setNameLoc(Loc);
if (ByRef) {
DeductType = BuildReferenceType(DeductType, true, Loc, Id);
assert(!DeductType.isNull() && "can't build reference to auto");
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 661a66246a5..44b58e1a80a 100755
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -1088,6 +1088,50 @@ bool Sema::ActOnTypeConstraint(const CXXScopeSpec &SS,
ConstrainedParameter, EllipsisLoc);
}
+template<typename ArgumentLocAppender>
+static ExprResult formImmediatelyDeclaredConstraint(
+ Sema &S, NestedNameSpecifierLoc NS, DeclarationNameInfo NameInfo,
+ ConceptDecl *NamedConcept, SourceLocation LAngleLoc,
+ SourceLocation RAngleLoc, QualType ConstrainedType,
+ SourceLocation ParamNameLoc, ArgumentLocAppender Appender,
+ SourceLocation EllipsisLoc) {
+
+ TemplateArgumentListInfo ConstraintArgs;
+ ConstraintArgs.addArgument(
+ S.getTrivialTemplateArgumentLoc(TemplateArgument(ConstrainedType),
+ /*NTTPType=*/QualType(), ParamNameLoc));
+
+ ConstraintArgs.setRAngleLoc(RAngleLoc);
+ ConstraintArgs.setLAngleLoc(LAngleLoc);
+ Appender(ConstraintArgs);
+
+ // C++2a [temp.param]p4:
+ // [...] This constraint-expression E is called the immediately-declared
+ // constraint of T. [...]
+ CXXScopeSpec SS;
+ SS.Adopt(NS);
+ ExprResult ImmediatelyDeclaredConstraint = S.CheckConceptTemplateId(
+ SS, /*TemplateKWLoc=*/SourceLocation(), NameInfo,
+ /*FoundDecl=*/NamedConcept, NamedConcept, &ConstraintArgs);
+ if (ImmediatelyDeclaredConstraint.isInvalid() || !EllipsisLoc.isValid())
+ return ImmediatelyDeclaredConstraint;
+
+ // C++2a [temp.param]p4:
+ // [...] If T is not a pack, then E is E', otherwise E is (E' && ...).
+ //
+ // We have the following case:
+ //
+ // template<typename T> concept C1 = true;
+ // template<C1... T> struct s1;
+ //
+ // The constraint: (C1<T> && ...)
+ return S.BuildCXXFoldExpr(/*LParenLoc=*/SourceLocation(),
+ ImmediatelyDeclaredConstraint.get(), BO_LAnd,
+ EllipsisLoc, /*RHS=*/nullptr,
+ /*RParenLoc=*/SourceLocation(),
+ /*NumExpansions=*/None);
+}
+
/// Attach a type-constraint to a template parameter.
/// \returns true if an error occured. This can happen if the
/// immediately-declared constraint could not be formed (e.g. incorrect number
@@ -1106,51 +1150,21 @@ bool Sema::AttachTypeConstraint(NestedNameSpecifierLoc NS,
*TemplateArgs) : nullptr;
QualType ParamAsArgument(ConstrainedParameter->getTypeForDecl(), 0);
- TemplateArgumentListInfo ConstraintArgs;
- ConstraintArgs.addArgument(
- TemplateArgumentLoc(
- TemplateArgument(ParamAsArgument),
- TemplateArgumentLocInfo(
- Context.getTrivialTypeSourceInfo(ParamAsArgument,
- ConstrainedParameter->getLocation()))));
- if (TemplateArgs) {
- ConstraintArgs.setRAngleLoc(TemplateArgs->getRAngleLoc());
- ConstraintArgs.setLAngleLoc(TemplateArgs->getLAngleLoc());
- for (const TemplateArgumentLoc &ArgLoc : TemplateArgs->arguments())
- ConstraintArgs.addArgument(ArgLoc);
- }
- // C++2a [temp.param]p4:
- // [...] This constraint-expression E is called the immediately-declared
- // constraint of T. [...]
- CXXScopeSpec SS;
- SS.Adopt(NS);
- ExprResult ImmediatelyDeclaredConstraint = CheckConceptTemplateId(SS,
- /*TemplateKWLoc=*/SourceLocation(), NameInfo, /*FoundDecl=*/NamedConcept,
- NamedConcept, &ConstraintArgs);
+ ExprResult ImmediatelyDeclaredConstraint =
+ formImmediatelyDeclaredConstraint(
+ *this, NS, NameInfo, NamedConcept,
+ TemplateArgs ? TemplateArgs->getLAngleLoc() : SourceLocation(),
+ TemplateArgs ? TemplateArgs->getRAngleLoc() : SourceLocation(),
+ ParamAsArgument, ConstrainedParameter->getLocation(),
+ [&] (TemplateArgumentListInfo &ConstraintArgs) {
+ if (TemplateArgs)
+ for (const auto &ArgLoc : TemplateArgs->arguments())
+ ConstraintArgs.addArgument(ArgLoc);
+ }, EllipsisLoc);
if (ImmediatelyDeclaredConstraint.isInvalid())
return true;
- if (ConstrainedParameter->isParameterPack()) {
- // C++2a [temp.param]p4:
- // [...] If T is not a pack, then E is E', otherwise E is (E' && ...).
- //
- // We have the following case:
- //
- // template<typename T> concept C1 = true;
- // template<C1... T> struct s1;
- //
- // The constraint: (C1<T> && ...)
- ImmediatelyDeclaredConstraint =
- BuildCXXFoldExpr(/*LParenLoc=*/SourceLocation(),
- ImmediatelyDeclaredConstraint.get(), BO_LAnd,
- EllipsisLoc, /*RHS=*/nullptr,
- /*RParenLoc=*/SourceLocation(),
- /*NumExpansions=*/None).get();
- if (ImmediatelyDeclaredConstraint.isInvalid())
- return true;
- }
-
ConstrainedParameter->setTypeConstraint(NS, NameInfo,
/*FoundDecl=*/NamedConcept,
NamedConcept, ArgsAsWritten,
@@ -1158,6 +1172,38 @@ bool Sema::AttachTypeConstraint(NestedNameSpecifierLoc NS,
return false;
}
+bool Sema::AttachTypeConstraint(AutoTypeLoc TL, NonTypeTemplateParmDecl *NTTP,
+ SourceLocation EllipsisLoc) {
+ if (NTTP->getType() != TL.getType() ||
+ TL.getAutoKeyword() != AutoTypeKeyword::Auto) {
+ Diag(NTTP->getTypeSourceInfo()->getTypeLoc().getBeginLoc(),
+ diag::err_unsupported_placeholder_constraint)
+ << NTTP->getTypeSourceInfo()->getTypeLoc().getSourceRange();
+ return true;
+ }
+ // FIXME: Concepts: This should be the type of the placeholder, but this is
+ // unclear in the wording right now.
+ DeclRefExpr *Ref = BuildDeclRefExpr(NTTP, NTTP->getType(), VK_RValue,
+ NTTP->getLocation());
+ if (!Ref)
+ return true;
+ ExprResult ImmediatelyDeclaredConstraint =
+ formImmediatelyDeclaredConstraint(
+ *this, TL.getNestedNameSpecifierLoc(), TL.getConceptNameInfo(),
+ TL.getNamedConcept(), TL.getLAngleLoc(), TL.getRAngleLoc(),
+ BuildDecltypeType(Ref, NTTP->getLocation()), NTTP->getLocation(),
+ [&] (TemplateArgumentListInfo &ConstraintArgs) {
+ for (unsigned I = 0, C = TL.getNumArgs(); I != C; ++I)
+ ConstraintArgs.addArgument(TL.getArgLoc(I));
+ }, EllipsisLoc);
+ if (ImmediatelyDeclaredConstraint.isInvalid() ||
+ !ImmediatelyDeclaredConstraint.isUsable())
+ return true;
+
+ NTTP->setPlaceholderTypeConstraint(ImmediatelyDeclaredConstraint.get());
+ return false;
+}
+
/// Check that the type of a non-type template parameter is
/// well-formed.
///
@@ -1319,6 +1365,11 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
TInfo);
Param->setAccess(AS_public);
+ if (AutoTypeLoc TL = TInfo->getTypeLoc().getContainedAutoTypeLoc())
+ if (TL.isConstrained())
+ if (AttachTypeConstraint(TL, Param, D.getEllipsisLoc()))
+ Invalid = true;
+
if (Invalid)
Param->setInvalidDecl();
@@ -2762,7 +2813,7 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
SourceLocation DeclStartLoc, SourceLocation DeclLoc, const CXXScopeSpec &SS,
TemplateIdAnnotation *TemplateId,
ArrayRef<TemplateParameterList *> ParamLists, bool IsFriend,
- bool &IsMemberSpecialization, bool &Invalid) {
+ bool &IsMemberSpecialization, bool &Invalid, bool SuppressDiagnostic) {
IsMemberSpecialization = false;
Invalid = false;
@@ -2870,8 +2921,9 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
auto CheckExplicitSpecialization = [&](SourceRange Range, bool Recovery) {
if (SawNonEmptyTemplateParameterList) {
- Diag(DeclLoc, diag::err_specialize_member_of_template)
- << !Recovery << Range;
+ if (!SuppressDiagnostic)
+ Diag(DeclLoc, diag::err_specialize_member_of_template)
+ << !Recovery << Range;
Invalid = true;
IsMemberSpecialization = false;
return true;
@@ -2892,9 +2944,10 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
else
ExpectedTemplateLoc = DeclStartLoc;
- Diag(DeclLoc, diag::err_template_spec_needs_header)
- << Range
- << FixItHint::CreateInsertion(ExpectedTemplateLoc, "template<> ");
+ if (!SuppressDiagnostic)
+ Diag(DeclLoc, diag::err_template_spec_needs_header)
+ << Range
+ << FixItHint::CreateInsertion(ExpectedTemplateLoc, "template<> ");
return false;
};
@@ -2984,12 +3037,13 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
if (ParamIdx < ParamLists.size()) {
if (ParamLists[ParamIdx]->size() > 0) {
// The header has template parameters when it shouldn't. Complain.
- Diag(ParamLists[ParamIdx]->getTemplateLoc(),
- diag::err_template_param_list_matches_nontemplate)
- << T
- << SourceRange(ParamLists[ParamIdx]->getLAngleLoc(),
- ParamLists[ParamIdx]->getRAngleLoc())
- << getRangeOfTypeInNestedNameSpecifier(Context, T, SS);
+ if (!SuppressDiagnostic)
+ Diag(ParamLists[ParamIdx]->getTemplateLoc(),
+ diag::err_template_param_list_matches_nontemplate)
+ << T
+ << SourceRange(ParamLists[ParamIdx]->getLAngleLoc(),
+ ParamLists[ParamIdx]->getRAngleLoc())
+ << getRangeOfTypeInNestedNameSpecifier(Context, T, SS);
Invalid = true;
return nullptr;
}
@@ -3025,7 +3079,7 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
if (ExpectedTemplateParams &&
!TemplateParameterListsAreEqual(ParamLists[ParamIdx],
ExpectedTemplateParams,
- true, TPL_TemplateMatch))
+ !SuppressDiagnostic, TPL_TemplateMatch))
Invalid = true;
if (!Invalid &&
@@ -3037,9 +3091,10 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
continue;
}
- Diag(DeclLoc, diag::err_template_spec_needs_template_parameters)
- << T
- << getRangeOfTypeInNestedNameSpecifier(Context, T, SS);
+ if (!SuppressDiagnostic)
+ Diag(DeclLoc, diag::err_template_spec_needs_template_parameters)
+ << T
+ << getRangeOfTypeInNestedNameSpecifier(Context, T, SS);
Invalid = true;
continue;
}
@@ -3075,16 +3130,18 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier(
AllExplicitSpecHeaders = false;
}
- Diag(ParamLists[ParamIdx]->getTemplateLoc(),
- AllExplicitSpecHeaders ? diag::warn_template_spec_extra_headers
- : diag::err_template_spec_extra_headers)
- << SourceRange(ParamLists[ParamIdx]->getTemplateLoc(),
- ParamLists[ParamLists.size() - 2]->getRAngleLoc());
+ if (!SuppressDiagnostic)
+ Diag(ParamLists[ParamIdx]->getTemplateLoc(),
+ AllExplicitSpecHeaders ? diag::warn_template_spec_extra_headers
+ : diag::err_template_spec_extra_headers)
+ << SourceRange(ParamLists[ParamIdx]->getTemplateLoc(),
+ ParamLists[ParamLists.size() - 2]->getRAngleLoc());
// If there was a specialization somewhere, such that 'template<>' is
// not required, and there were any 'template<>' headers, note where the
// specialization occurred.
- if (ExplicitSpecLoc.isValid() && HasAnyExplicitSpecHeader)
+ if (ExplicitSpecLoc.isValid() && HasAnyExplicitSpecHeader &&
+ !SuppressDiagnostic)
Diag(ExplicitSpecLoc,
diag::note_explicit_template_spec_does_not_need_header)
<< NestedTypes.back();
@@ -6530,7 +6587,12 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
DeductionArg = PE->getPattern();
if (DeduceAutoType(
Context.getTrivialTypeSourceInfo(ParamType, Param->getLocation()),
- DeductionArg, ParamType, Depth) == DAR_Failed) {
+ DeductionArg, ParamType, Depth,
+ // We do not check constraints right now because the
+ // immediately-declared constraint of the auto type is also an
+ // associated constraint, and will be checked along with the other
+ // associated constraints after checking the template argument list.
+ /*IgnoreConstraints=*/true) == DAR_Failed) {
Diag(Arg->getExprLoc(),
diag::err_non_type_template_parm_type_deduction_failure)
<< Param->getDeclName() << Param->getType() << Arg->getType()
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 048a50a741e..394c81c8279 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -4414,9 +4414,10 @@ namespace {
QualType Result = SemaRef.Context.getAutoType(
Replacement, TL.getTypePtr()->getKeyword(), Replacement.isNull(),
- ReplacementIsPack);
+ ReplacementIsPack, TL.getTypePtr()->getTypeConstraintConcept(),
+ TL.getTypePtr()->getTypeConstraintArguments());
auto NewTL = TLB.push<AutoTypeLoc>(Result);
- NewTL.setNameLoc(TL.getNameLoc());
+ NewTL.copy(TL);
return Result;
}
@@ -4451,9 +4452,10 @@ namespace {
Sema::DeduceAutoResult
Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init, QualType &Result,
- Optional<unsigned> DependentDeductionDepth) {
+ Optional<unsigned> DependentDeductionDepth,
+ bool IgnoreConstraints) {
return DeduceAutoType(Type->getTypeLoc(), Init, Result,
- DependentDeductionDepth);
+ DependentDeductionDepth, IgnoreConstraints);
}
/// Attempt to produce an informative diagostic explaining why auto deduction
@@ -4481,6 +4483,49 @@ static bool diagnoseAutoDeductionFailure(Sema &S,
}
}
+static Sema::DeduceAutoResult
+CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type,
+ AutoTypeLoc TypeLoc, QualType Deduced) {
+ ConstraintSatisfaction Satisfaction;
+ ConceptDecl *Concept = Type.getTypeConstraintConcept();
+ TemplateArgumentListInfo TemplateArgs(TypeLoc.getLAngleLoc(),
+ TypeLoc.getRAngleLoc());
+ TemplateArgs.addArgument(
+ TemplateArgumentLoc(TemplateArgument(Deduced),
+ S.Context.getTrivialTypeSourceInfo(
+ Deduced, TypeLoc.getNameLoc())));
+ for (unsigned I = 0, C = TypeLoc.getNumArgs(); I != C; ++I)
+ TemplateArgs.addArgument(TypeLoc.getArgLoc(I));
+
+ llvm::SmallVector<TemplateArgument, 4> Converted;
+ if (S.CheckTemplateArgumentList(Concept, SourceLocation(), TemplateArgs,
+ /*PartialTemplateArgs=*/false, Converted))
+ return Sema::DAR_FailedAlreadyDiagnosed;
+ if (S.CheckConstraintSatisfaction(Concept, {Concept->getConstraintExpr()},
+ Converted, TypeLoc.getLocalSourceRange(),
+ Satisfaction))
+ return Sema::DAR_FailedAlreadyDiagnosed;
+ if (!Satisfaction.IsSatisfied) {
+ std::string Buf;
+ llvm::raw_string_ostream OS(Buf);
+ OS << "'" << Concept->getName();
+ if (TypeLoc.hasExplicitTemplateArgs()) {
+ OS << "<";
+ for (const auto &Arg : Type.getTypeConstraintArguments())
+ Arg.print(S.getPrintingPolicy(), OS);
+ OS << ">";
+ }
+ OS << "'";
+ OS.flush();
+ S.Diag(TypeLoc.getConceptNameLoc(),
+ diag::err_placeholder_constraints_not_satisfied)
+ << Deduced << Buf << TypeLoc.getLocalSourceRange();
+ S.DiagnoseUnsatisfiedConstraint(Satisfaction);
+ return Sema::DAR_FailedAlreadyDiagnosed;
+ }
+ return Sema::DAR_Succeeded;
+}
+
/// Deduce the type for an auto type-specifier (C++11 [dcl.spec.auto]p6)
///
/// Note that this is done even if the initializer is dependent. (This is
@@ -4495,9 +4540,12 @@ static bool diagnoseAutoDeductionFailure(Sema &S,
/// dependent cases. This is necessary for template partial ordering with
/// 'auto' template parameters. The value specified is the template
/// parameter depth at which we should perform 'auto' deduction.
+/// \param IgnoreConstraints Set if we should not fail if the deduced type does
+/// not satisfy the type-constraint in the auto type.
Sema::DeduceAutoResult
Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
- Optional<unsigned> DependentDeductionDepth) {
+ Optional<unsigned> DependentDeductionDepth,
+ bool IgnoreConstraints) {
if (Init->getType()->isNonOverloadPlaceholderType()) {
ExprResult NonPlaceholder = CheckPlaceholderExpr(Init);
if (NonPlaceholder.isInvalid())
@@ -4538,6 +4586,14 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
return DAR_FailedAlreadyDiagnosed;
// FIXME: Support a non-canonical deduced type for 'auto'.
Deduced = Context.getCanonicalType(Deduced);
+ if (AT->isConstrained() && !IgnoreConstraints) {
+ auto ConstraintsResult =
+ CheckDeducedPlaceholderConstraints(*this, *AT,
+ Type.getContainedAutoTypeLoc(),
+ Deduced);
+ if (ConstraintsResult != DAR_Succeeded)
+ return ConstraintsResult;
+ }
Result = SubstituteDeducedTypeTransform(*this, Deduced).Apply(Type);
if (Result.isNull())
return DAR_FailedAlreadyDiagnosed;
@@ -4645,6 +4701,17 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result,
return DAR_FailedAlreadyDiagnosed;
}
+ if (const auto *AT = Type.getType()->getAs<AutoType>()) {
+ if (AT->isConstrained() && !IgnoreConstraints) {
+ auto ConstraintsResult =
+ CheckDeducedPlaceholderConstraints(*this, *AT,
+ Type.getContainedAutoTypeLoc(),
+ DeducedType);
+ if (ConstraintsResult != DAR_Succeeded)
+ return ConstraintsResult;
+ }
+ }
+
Result = SubstituteDeducedTypeTransform(*this, DeducedType).Apply(Type);
if (Result.isNull())
return DAR_FailedAlreadyDiagnosed;
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 7d60298be2b..8fd7491c45e 100755
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -2685,6 +2685,16 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl(
D->getDepth() - TemplateArgs.getNumSubstitutedLevels(),
D->getPosition(), D->getIdentifier(), T, D->isParameterPack(), DI);
+ if (AutoTypeLoc AutoLoc = DI->getTypeLoc().getContainedAutoTypeLoc())
+ if (AutoLoc.isConstrained())
+ if (SemaRef.AttachTypeConstraint(
+ AutoLoc, Param,
+ IsExpandedParameterPack
+ ? DI->getTypeLoc().getAs<PackExpansionTypeLoc>()
+ .getEllipsisLoc()
+ : SourceLocation()))
+ Invalid = true;
+
Param->setAccess(AS_public);
Param->setImplicit(D->isImplicit());
if (Invalid)
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index bafeed6e844..632dc51c951 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===//
#include "TypeLocBuilder.h"
+#include "TreeTransform.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTMutationListener.h"
@@ -27,6 +28,7 @@
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/DelayedDiagnostic.h"
#include "clang/Sema/Lookup.h"
+#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/Template.h"
@@ -1251,6 +1253,26 @@ getImageAccess(const ParsedAttributesView &Attrs) {
return OpenCLAccessAttr::Keyword_read_only;
}
+static QualType ConvertConstrainedAutoDeclSpecToType(Sema &S, DeclSpec &DS,
+ AutoTypeKeyword AutoKW) {
+ assert(DS.isConstrainedAuto());
+ TemplateIdAnnotation *TemplateId = DS.getRepAsTemplateId();
+ TemplateArgumentListInfo TemplateArgsInfo;
+ TemplateArgsInfo.setLAngleLoc(TemplateId->LAngleLoc);
+ TemplateArgsInfo.setRAngleLoc(TemplateId->RAngleLoc);
+ ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
+ TemplateId->NumArgs);
+ S.translateTemplateArguments(TemplateArgsPtr, TemplateArgsInfo);
+ llvm::SmallVector<TemplateArgument, 8> TemplateArgs;
+ for (auto &ArgLoc : TemplateArgsInfo.arguments())
+ TemplateArgs.push_back(ArgLoc.getArgument());
+ return S.Context.getAutoType(QualType(), AutoTypeKeyword::Auto, false,
+ /*IsPack=*/false,
+ cast<ConceptDecl>(TemplateId->Template.get()
+ .getAsTemplateDecl()),
+ TemplateArgs);
+}
+
/// Convert the specified declspec to the appropriate type
/// object.
/// \param state Specifies the declarator containing the declaration specifier
@@ -1595,6 +1617,11 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
break;
case DeclSpec::TST_auto:
+ if (DS.isConstrainedAuto()) {
+ Result = ConvertConstrainedAutoDeclSpecToType(S, DS,
+ AutoTypeKeyword::Auto);
+ break;
+ }
Result = Context.getAutoType(QualType(), AutoTypeKeyword::Auto, false);
break;
@@ -1603,6 +1630,12 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
break;
case DeclSpec::TST_decltype_auto:
+ if (DS.isConstrainedAuto()) {
+ Result =
+ ConvertConstrainedAutoDeclSpecToType(S, DS,
+ AutoTypeKeyword::DecltypeAuto);
+ break;
+ }
Result = Context.getAutoType(QualType(), AutoTypeKeyword::DecltypeAuto,
/*IsDependent*/ false);
break;
@@ -2921,6 +2954,87 @@ static void diagnoseRedundantReturnTypeQualifiers(Sema &S, QualType RetTy,
D.getDeclSpec().getUnalignedSpecLoc());
}
+static void CopyTypeConstraintFromAutoType(Sema &SemaRef, const AutoType *Auto,
+ AutoTypeLoc AutoLoc,
+ TemplateTypeParmDecl *TP,
+ SourceLocation EllipsisLoc) {
+
+ TemplateArgumentListInfo TAL(AutoLoc.getLAngleLoc(), AutoLoc.getRAngleLoc());
+ for (unsigned Idx = 0; Idx < AutoLoc.getNumArgs(); ++Idx)
+ TAL.addArgument(AutoLoc.getArgLoc(Idx));
+
+ SemaRef.AttachTypeConstraint(
+ AutoLoc.getNestedNameSpecifierLoc(), AutoLoc.getConceptNameInfo(),
+ AutoLoc.getNamedConcept(),
+ AutoLoc.hasExplicitTemplateArgs() ? &TAL : nullptr, TP, EllipsisLoc);
+}
+
+static QualType InventTemplateParameter(
+ TypeProcessingState &state, QualType T, TypeSourceInfo *TSI, AutoType *Auto,
+ InventedTemplateParameterInfo &Info) {
+ Sema &S = state.getSema();
+ Declarator &D = state.getDeclarator();
+
+ const unsigned TemplateParameterDepth = Info.AutoTemplateParameterDepth;
+ const unsigned AutoParameterPosition = Info.TemplateParams.size();
+ const bool IsParameterPack = D.hasEllipsis();
+
+ // If auto is mentioned in a lambda parameter or abbreviated function
+ // template context, convert it to a template parameter type.
+
+ // Create the TemplateTypeParmDecl here to retrieve the corresponding
+ // template parameter type. Template parameters are temporarily added
+ // to the TU until the associated TemplateDecl is created.
+ TemplateTypeParmDecl *InventedTemplateParam =
+ TemplateTypeParmDecl::Create(
+ S.Context, S.Context.getTranslationUnitDecl(),
+ /*KeyLoc=*/D.getDeclSpec().getTypeSpecTypeLoc(),
+ /*NameLoc=*/D.getIdentifierLoc(),
+ TemplateParameterDepth, AutoParameterPosition,
+ S.InventAbbreviatedTemplateParameterTypeName(
+ D.getIdentifier(), AutoParameterPosition), false,
+ IsParameterPack, /*HasTypeConstraint=*/Auto->isConstrained());
+ InventedTemplateParam->setImplicit();
+ Info.TemplateParams.push_back(InventedTemplateParam);
+ // Attach type constraints
+ if (Auto->isConstrained()) {
+ if (TSI) {
+ CopyTypeConstraintFromAutoType(
+ S, Auto, TSI->getTypeLoc().getContainedAutoTypeLoc(),
+ InventedTemplateParam, D.getEllipsisLoc());
+ } else {
+ TemplateIdAnnotation *TemplateId = D.getDeclSpec().getRepAsTemplateId();
+ TemplateArgumentListInfo TemplateArgsInfo;
+ if (TemplateId->LAngleLoc.isValid()) {
+ ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
+ TemplateId->NumArgs);
+ S.translateTemplateArguments(TemplateArgsPtr, TemplateArgsInfo);
+ }
+ S.AttachTypeConstraint(
+ D.getDeclSpec().getTypeSpecScope().getWithLocInContext(S.Context),
+ DeclarationNameInfo(DeclarationName(TemplateId->Name),
+ TemplateId->TemplateNameLoc),
+ cast<ConceptDecl>(TemplateId->Template.get().getAsTemplateDecl()),
+ TemplateId->LAngleLoc.isValid() ? &TemplateArgsInfo : nullptr,
+ InventedTemplateParam, D.getEllipsisLoc());
+ }
+ }
+
+ // If TSI is nullptr, this is a constrained declspec auto and the type
+ // constraint will be attached later in TypeSpecLocFiller
+
+ // Replace the 'auto' in the function parameter with this invented
+ // template type parameter.
+ // FIXME: Retain some type sugar to indicate that this was written
+ // as 'auto'?
+ return state.ReplaceAutoType(
+ T, QualType(InventedTemplateParam->getTypeForDecl(), 0));
+}
+
+static TypeSourceInfo *
+GetTypeSourceInfoForDeclarator(TypeProcessingState &State,
+ QualType T, TypeSourceInfo *ReturnTypeInfo);
+
static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
TypeSourceInfo *&ReturnTypeInfo) {
Sema &SemaRef = state.getSema();
@@ -2991,46 +3105,43 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
break;
case DeclaratorContext::ObjCParameterContext:
case DeclaratorContext::ObjCResultContext:
- case DeclaratorContext::PrototypeContext:
Error = 0;
break;
case DeclaratorContext::RequiresExprContext:
- Error = 21;
+ Error = 22;
break;
- case DeclaratorContext::LambdaExprParameterContext:
- // In C++14, generic lambdas allow 'auto' in their parameters.
- if (!SemaRef.getLangOpts().CPlusPlus14 ||
- !Auto || Auto->getKeyword() != AutoTypeKeyword::Auto)
- Error = 16;
- else {
- // If auto is mentioned in a lambda parameter context, convert it to a
- // template parameter type.
- sema::LambdaScopeInfo *LSI = SemaRef.getCurLambda();
- assert(LSI && "No LambdaScopeInfo on the stack!");
- const unsigned TemplateParameterDepth = LSI->AutoTemplateParameterDepth;
- const unsigned AutoParameterPosition = LSI->TemplateParams.size();
- const bool IsParameterPack = D.hasEllipsis();
-
- // Create the TemplateTypeParmDecl here to retrieve the corresponding
- // template parameter type. Template parameters are temporarily added
- // to the TU until the associated TemplateDecl is created.
- TemplateTypeParmDecl *CorrespondingTemplateParam =
- TemplateTypeParmDecl::Create(
- SemaRef.Context, SemaRef.Context.getTranslationUnitDecl(),
- /*KeyLoc*/ SourceLocation(), /*NameLoc*/ D.getBeginLoc(),
- TemplateParameterDepth, AutoParameterPosition,
- /*Identifier*/ nullptr, false, IsParameterPack,
- /*HasTypeConstraint=*/false);
- CorrespondingTemplateParam->setImplicit();
- LSI->TemplateParams.push_back(CorrespondingTemplateParam);
- // Replace the 'auto' in the function parameter with this invented
- // template type parameter.
- // FIXME: Retain some type sugar to indicate that this was written
- // as 'auto'.
- T = state.ReplaceAutoType(
- T, QualType(CorrespondingTemplateParam->getTypeForDecl(), 0));
+ case DeclaratorContext::PrototypeContext:
+ case DeclaratorContext::LambdaExprParameterContext: {
+ InventedTemplateParameterInfo *Info = nullptr;
+ if (D.getContext() == DeclaratorContext::PrototypeContext) {
+ // With concepts we allow 'auto' in function parameters.
+ if (!SemaRef.getLangOpts().ConceptsTS || !Auto ||
+ Auto->getKeyword() != AutoTypeKeyword::Auto) {
+ Error = 0;
+ break;
+ } else if (!SemaRef.getCurScope()->isFunctionDeclarationScope()) {
+ Error = 21;
+ break;
+ } else if (D.hasTrailingReturnType()) {
+ // This might be OK, but we'll need to convert the trailing return
+ // type later.
+ break;
+ }
+
+ Info = &SemaRef.InventedParameterInfos.back();
+ } else {
+ // In C++14, generic lambdas allow 'auto' in their parameters.
+ if (!SemaRef.getLangOpts().CPlusPlus14 || !Auto ||
+ Auto->getKeyword() != AutoTypeKeyword::Auto) {
+ Error = 16;
+ break;
+ }
+ Info = SemaRef.getCurLambda();
+ assert(Info && "No LambdaScopeInfo on the stack!");
}
+ T = InventTemplateParameter(state, T, nullptr, Auto, *Info);
break;
+ }
case DeclaratorContext::MemberContext: {
if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static ||
D.isFunctionDeclarator())
@@ -4032,10 +4143,6 @@ static bool DiagnoseMultipleAddrSpaceAttributes(Sema &S, LangAS ASOld,
return false;
}
-static TypeSourceInfo *
-GetTypeSourceInfoForDeclarator(TypeProcessingState &State,
- QualType T, TypeSourceInfo *ReturnTypeInfo);
-
static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
QualType declSpecType,
TypeSourceInfo *TInfo) {
@@ -4611,7 +4718,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
} else if (D.getContext() != DeclaratorContext::LambdaExprContext &&
(T.hasQualifiers() || !isa<AutoType>(T) ||
cast<AutoType>(T)->getKeyword() !=
- AutoTypeKeyword::Auto)) {
+ AutoTypeKeyword::Auto ||
+ cast<AutoType>(T)->isConstrained())) {
S.Diag(D.getDeclSpec().getTypeSpecTypeLoc(),
diag::err_trailing_return_without_auto)
<< T << D.getDeclSpec().getSourceRange();
@@ -4622,7 +4730,12 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// An error occurred parsing the trailing return type.
T = Context.IntTy;
D.setInvalidType(true);
- }
+ } else if (S.getLangOpts().ConceptsTS)
+ // Handle cases like: `auto f() -> auto` or `auto f() -> C auto`.
+ if (AutoType *Auto = T->getContainedAutoType())
+ if (S.getCurScope()->isFunctionDeclarationScope())
+ T = InventTemplateParameter(state, T, TInfo, Auto,
+ S.InventedParameterInfos.back());
} else {
// This function type is not the type of the entity being declared,
// so checking the 'auto' is not the responsibility of this chunk.
@@ -5242,7 +5355,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
//
// We represent function parameter packs as function parameters whose
// type is a pack expansion.
- if (!T->containsUnexpandedParameterPack()) {
+ if (!T->containsUnexpandedParameterPack() &&
+ (!LangOpts.ConceptsTS || !T->getContainedAutoType())) {
S.Diag(D.getEllipsisLoc(),
diag::err_function_parameter_pack_without_parameter_packs)
<< T << D.getSourceRange();
@@ -5450,14 +5564,15 @@ static void fillAttributedTypeLoc(AttributedTypeLoc TL,
namespace {
class TypeSpecLocFiller : public TypeLocVisitor<TypeSpecLocFiller> {
+ Sema &SemaRef;
ASTContext &Context;
TypeProcessingState &State;
const DeclSpec &DS;
public:
- TypeSpecLocFiller(ASTContext &Context, TypeProcessingState &State,
+ TypeSpecLocFiller(Sema &S, ASTContext &Context, TypeProcessingState &State,
const DeclSpec &DS)
- : Context(Context), State(State), DS(DS) {}
+ : SemaRef(S), Context(Context), State(State), DS(DS) {}
void VisitAttributedTypeLoc(AttributedTypeLoc TL) {
Visit(TL.getModifiedLoc());
@@ -5585,6 +5700,34 @@ namespace {
TL.copy(
TInfo->getTypeLoc().castAs<DependentTemplateSpecializationTypeLoc>());
}
+ void VisitAutoTypeLoc(AutoTypeLoc TL) {
+ assert(DS.getTypeSpecType() == TST_auto ||
+ DS.getTypeSpecType() == TST_decltype_auto ||
+ DS.getTypeSpecType() == TST_auto_type ||
+ DS.getTypeSpecType() == TST_unspecified);
+ TL.setNameLoc(DS.getTypeSpecTypeLoc());
+ if (!DS.isConstrainedAuto())
+ return;
+ TemplateIdAnnotation *TemplateId = DS.getRepAsTemplateId();
+ if (DS.getTypeSpecScope().isNotEmpty())
+ TL.setNestedNameSpecifierLoc(
+ DS.getTypeSpecScope().getWithLocInContext(Context));
+ else
+ TL.setNestedNameSpecifierLoc(NestedNameSpecifierLoc());
+ TL.setTemplateKWLoc(TemplateId->TemplateKWLoc);
+ TL.setConceptNameLoc(TemplateId->TemplateNameLoc);
+ TL.setFoundDecl(nullptr);
+ TL.setLAngleLoc(TemplateId->LAngleLoc);
+ TL.setRAngleLoc(TemplateId->RAngleLoc);
+ if (TemplateId->NumArgs == 0)
+ return;
+ TemplateArgumentListInfo TemplateArgsInfo;
+ ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
+ TemplateId->NumArgs);
+ SemaRef.translateTemplateArguments(TemplateArgsPtr, TemplateArgsInfo);
+ for (unsigned I = 0; I < TemplateId->NumArgs; ++I)
+ TL.setArgLocInfo(I, TemplateArgsInfo.arguments()[I].getLocInfo());
+ }
void VisitTagTypeLoc(TagTypeLoc TL) {
TL.setNameLoc(DS.getTypeSpecTypeNameLoc());
}
@@ -5854,7 +5997,7 @@ GetTypeSourceInfoForDeclarator(TypeProcessingState &State,
assert(TL.getFullDataSize() == CurrTL.getFullDataSize());
memcpy(CurrTL.getOpaqueData(), TL.getOpaqueData(), TL.getFullDataSize());
} else {
- TypeSpecLocFiller(S.Context, State, D.getDeclSpec()).Visit(CurrTL);
+ TypeSpecLocFiller(S, S.Context, State, D.getDeclSpec()).Visit(CurrTL);
}
return TInfo;
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 1f725117383..d6105353bbd 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -951,12 +951,16 @@ public:
/// Build a new C++11 auto type.
///
/// By default, builds a new AutoType with the given deduced type.
- QualType RebuildAutoType(QualType Deduced, AutoTypeKeyword Keyword) {
+ QualType RebuildAutoType(QualType Deduced, AutoTypeKeyword Keyword,
+ ConceptDecl *TypeConstraintConcept,
+ ArrayRef<TemplateArgument> TypeConstraintArgs) {
// Note, IsDependent is always false here: we implicitly convert an 'auto'
// which has been deduced to a dependent type into an undeduced 'auto', so
// that we'll retry deduction after the transformation.
return SemaRef.Context.getAutoType(Deduced, Keyword,
- /*IsDependent*/ false);
+ /*IsDependent*/ false, /*IsPack=*/false,
+ TypeConstraintConcept,
+ TypeConstraintArgs);
}
/// By default, builds a new DeducedTemplateSpecializationType with the given
@@ -4500,7 +4504,10 @@ QualType TreeTransform<Derived>::RebuildQualifiedType(QualType T,
Deduced =
SemaRef.Context.getQualifiedType(Deduced.getUnqualifiedType(), Qs);
T = SemaRef.Context.getAutoType(Deduced, AutoTy->getKeyword(),
- AutoTy->isDependentType());
+ AutoTy->isDependentType(),
+ /*isPack=*/false,
+ AutoTy->getTypeConstraintConcept(),
+ AutoTy->getTypeConstraintArguments());
} else {
// Otherwise, complain about the addition of a qualifier to an
// already-qualified type.
@@ -5233,21 +5240,29 @@ bool TreeTransform<Derived>::TransformFunctionTypeParams(
PackExpansionTypeLoc ExpansionTL = TL.castAs<PackExpansionTypeLoc>();
TypeLoc Pattern = ExpansionTL.getPatternLoc();
SemaRef.collectUnexpandedParameterPacks(Pattern, Unexpanded);
- assert(Unexpanded.size() > 0 && "Could not find parameter packs!");
// Determine whether we should expand the parameter packs.
bool ShouldExpand = false;
bool RetainExpansion = false;
- Optional<unsigned> OrigNumExpansions =
- ExpansionTL.getTypePtr()->getNumExpansions();
- NumExpansions = OrigNumExpansions;
- if (getDerived().TryExpandParameterPacks(ExpansionTL.getEllipsisLoc(),
- Pattern.getSourceRange(),
- Unexpanded,
- ShouldExpand,
- RetainExpansion,
- NumExpansions)) {
- return true;
+ Optional<unsigned> OrigNumExpansions;
+ if (Unexpanded.size() > 0) {
+ OrigNumExpansions = ExpansionTL.getTypePtr()->getNumExpansions();
+ NumExpansions = OrigNumExpansions;
+ if (getDerived().TryExpandParameterPacks(ExpansionTL.getEllipsisLoc(),
+ Pattern.getSourceRange(),
+ Unexpanded,
+ ShouldExpand,
+ RetainExpansion,
+ NumExpansions)) {
+ return true;
+ }
+ } else {
+#ifndef NDEBUG
+ const AutoType *AT =
+ Pattern.getType().getTypePtr()->getContainedAutoType();
+ assert((AT && (!AT->isDeduced() || AT->getDeducedType().isNull())) &&
+ "Could not find parameter packs or undeduced auto type!");
+#endif
}
if (ShouldExpand) {
@@ -5307,6 +5322,9 @@ bool TreeTransform<Derived>::TransformFunctionTypeParams(
indexAdjustment,
NumExpansions,
/*ExpectParameterPack=*/true);
+ assert(NewParm->isParameterPack() &&
+ "Parameter pack no longer a parameter pack after "
+ "transformation.");
} else {
NewParm = getDerived().TransformFunctionTypeParam(
OldParm, indexAdjustment, None, /*ExpectParameterPack=*/ false);
@@ -5812,32 +5830,6 @@ QualType TreeTransform<Derived>::TransformUnaryTransformType(
}
template<typename Derived>
-QualType TreeTransform<Derived>::TransformAutoType(TypeLocBuilder &TLB,
- AutoTypeLoc TL) {
- const AutoType *T = TL.getTypePtr();
- QualType OldDeduced = T->getDeducedType();
- QualType NewDeduced;
- if (!OldDeduced.isNull()) {
- NewDeduced = getDerived().TransformType(OldDeduced);
- if (NewDeduced.isNull())
- return QualType();
- }
-
- QualType Result = TL.getType();
- if (getDerived().AlwaysRebuild() || NewDeduced != OldDeduced ||
- T->isDependentType()) {
- Result = getDerived().RebuildAutoType(NewDeduced, T->getKeyword());
- if (Result.isNull())
- return QualType();
- }
-
- AutoTypeLoc NewTL = TLB.push<AutoTypeLoc>(Result);
- NewTL.setNameLoc(TL.getNameLoc());
-
- return Result;
-}
-
-template<typename Derived>
QualType TreeTransform<Derived>::TransformDeducedTemplateSpecializationType(
TypeLocBuilder &TLB, DeducedTemplateSpecializationTypeLoc TL) {
const DeducedTemplateSpecializationType *T = TL.getTypePtr();
@@ -6098,6 +6090,71 @@ QualType TreeTransform<Derived>::TransformPipeType(TypeLocBuilder &TLB,
}
};
+template<typename Derived>
+QualType TreeTransform<Derived>::TransformAutoType(TypeLocBuilder &TLB,
+ AutoTypeLoc TL) {
+ const AutoType *T = TL.getTypePtr();
+ QualType OldDeduced = T->getDeducedType();
+ QualType NewDeduced;
+ if (!OldDeduced.isNull()) {
+ NewDeduced = getDerived().TransformType(OldDeduced);
+ if (NewDeduced.isNull())
+ return QualType();
+ }
+
+ ConceptDecl *NewCD = nullptr;
+ TemplateArgumentListInfo NewTemplateArgs;
+ NestedNameSpecifierLoc NewNestedNameSpec;
+ if (TL.getTypePtr()->isConstrained()) {
+ NewCD = cast_or_null<ConceptDecl>(
+ getDerived().TransformDecl(
+ TL.getConceptNameLoc(),
+ TL.getTypePtr()->getTypeConstraintConcept()));
+
+ NewTemplateArgs.setLAngleLoc(TL.getLAngleLoc());
+ NewTemplateArgs.setRAngleLoc(TL.getRAngleLoc());
+ typedef TemplateArgumentLocContainerIterator<AutoTypeLoc> ArgIterator;
+ if (getDerived().TransformTemplateArguments(ArgIterator(TL, 0),
+ ArgIterator(TL,
+ TL.getNumArgs()),
+ NewTemplateArgs))
+ return QualType();
+
+ if (TL.getNestedNameSpecifierLoc()) {
+ NewNestedNameSpec
+ = getDerived().TransformNestedNameSpecifierLoc(
+ TL.getNestedNameSpecifierLoc());
+ if (!NewNestedNameSpec)
+ return QualType();
+ }
+ }
+
+ QualType Result = TL.getType();
+ if (getDerived().AlwaysRebuild() || NewDeduced != OldDeduced ||
+ T->isDependentType()) {
+ llvm::SmallVector<TemplateArgument, 4> NewArgList;
+ NewArgList.reserve(NewArgList.size());
+ for (const auto &ArgLoc : NewTemplateArgs.arguments())
+ NewArgList.push_back(ArgLoc.getArgument());
+ Result = getDerived().RebuildAutoType(NewDeduced, T->getKeyword(), NewCD,
+ NewArgList);
+ if (Result.isNull())
+ return QualType();
+ }
+
+ AutoTypeLoc NewTL = TLB.push<AutoTypeLoc>(Result);
+ NewTL.setNameLoc(TL.getNameLoc());
+ NewTL.setNestedNameSpecifierLoc(NewNestedNameSpec);
+ NewTL.setTemplateKWLoc(TL.getTemplateKWLoc());
+ NewTL.setConceptNameLoc(TL.getConceptNameLoc());
+ NewTL.setFoundDecl(TL.getFoundDecl());
+ NewTL.setLAngleLoc(TL.getLAngleLoc());
+ NewTL.setRAngleLoc(TL.getRAngleLoc());
+ for (unsigned I = 0; I < TL.getNumArgs(); ++I)
+ NewTL.setArgLocInfo(I, NewTemplateArgs.arguments()[I].getLocInfo());
+
+ return Result;
+}
template <typename Derived>
QualType TreeTransform<Derived>::TransformTemplateSpecializationType(
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index 19e7ebe03a1..8e8b04451fb 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -6576,6 +6576,17 @@ void TypeLocReader::VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) {
void TypeLocReader::VisitAutoTypeLoc(AutoTypeLoc TL) {
TL.setNameLoc(readSourceLocation());
+ if (Reader.readBool()) {
+ TL.setNestedNameSpecifierLoc(ReadNestedNameSpecifierLoc());
+ TL.setTemplateKWLoc(readSourceLocation());
+ TL.setConceptNameLoc(readSourceLocation());
+ TL.setFoundDecl(Reader.readDeclAs<NamedDecl>());
+ TL.setLAngleLoc(readSourceLocation());
+ TL.setRAngleLoc(readSourceLocation());
+ for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i)
+ TL.setArgLocInfo(i, Reader.readTemplateArgumentLocInfo(
+ TL.getTypePtr()->getArg(i).getKind()));
+ }
}
void TypeLocReader::VisitDeducedTemplateSpecializationTypeLoc(
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index 4fd079e9d8e..093b69ab19d 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -2317,12 +2317,12 @@ void ASTDeclReader::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
D->setDeclaredWithTypename(Record.readInt());
- if (Record.readInt()) {
+ if (Record.readBool()) {
NestedNameSpecifierLoc NNS = Record.readNestedNameSpecifierLoc();
DeclarationNameInfo DN = Record.readDeclarationNameInfo();
- ConceptDecl *NamedConcept = cast<ConceptDecl>(Record.readDecl());
+ ConceptDecl *NamedConcept = Record.readDeclAs<ConceptDecl>();
const ASTTemplateArgumentListInfo *ArgsAsWritten = nullptr;
- if (Record.readInt())
+ if (Record.readBool())
ArgsAsWritten = Record.readASTTemplateArgumentListInfo();
Expr *ImmediatelyDeclaredConstraint = Record.readExpr();
D->setTypeConstraint(NNS, DN, /*FoundDecl=*/nullptr, NamedConcept,
@@ -2340,6 +2340,8 @@ void ASTDeclReader::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
// TemplateParmPosition.
D->setDepth(Record.readInt());
D->setPosition(Record.readInt());
+ if (D->hasPlaceholderTypeConstraint())
+ D->setPlaceholderTypeConstraint(Record.readExpr());
if (D->isExpandedParameterPack()) {
auto TypesAndInfos =
D->getTrailingObjects<std::pair<QualType, TypeSourceInfo *>>();
@@ -3823,13 +3825,19 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
HasTypeConstraint);
break;
}
- case DECL_NON_TYPE_TEMPLATE_PARM:
- D = NonTypeTemplateParmDecl::CreateDeserialized(Context, ID);
+ case DECL_NON_TYPE_TEMPLATE_PARM: {
+ bool HasTypeConstraint = Record.readInt();
+ D = NonTypeTemplateParmDecl::CreateDeserialized(Context, ID,
+ HasTypeConstraint);
break;
- case DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK:
+ }
+ case DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK: {
+ bool HasTypeConstraint = Record.readInt();
D = NonTypeTemplateParmDecl::CreateDeserialized(Context, ID,
- Record.readInt());
+ Record.readInt(),
+ HasTypeConstraint);
break;
+ }
case DECL_TEMPLATE_TEMPLATE_PARM:
D = TemplateTemplateParmDecl::CreateDeserialized(Context, ID);
break;
diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index 2dfdcc1f4fb..252853aad1f 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -349,6 +349,18 @@ void TypeLocWriter::VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) {
void TypeLocWriter::VisitAutoTypeLoc(AutoTypeLoc TL) {
Record.AddSourceLocation(TL.getNameLoc());
+ Record.push_back(TL.isConstrained());
+ if (TL.isConstrained()) {
+ Record.AddNestedNameSpecifierLoc(TL.getNestedNameSpecifierLoc());
+ Record.AddSourceLocation(TL.getTemplateKWLoc());
+ Record.AddSourceLocation(TL.getConceptNameLoc());
+ Record.AddDeclRef(TL.getFoundDecl());
+ Record.AddSourceLocation(TL.getLAngleLoc());
+ Record.AddSourceLocation(TL.getRAngleLoc());
+ for (unsigned I = 0; I < TL.getNumArgs(); ++I)
+ Record.AddTemplateArgumentLocInfo(TL.getTypePtr()->getArg(I).getKind(),
+ TL.getArgLocInfo(I));
+ }
}
void TypeLocWriter::VisitDeducedTemplateSpecializationTypeLoc(
diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp
index 459e61713ed..472136d99a1 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -1675,6 +1675,8 @@ void ASTDeclWriter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
// For an expanded parameter pack, record the number of expansion types here
// so that it's easier for deserialization to allocate the right amount of
// memory.
+ Expr *TypeConstraint = D->getPlaceholderTypeConstraint();
+ Record.push_back(!!TypeConstraint);
if (D->isExpandedParameterPack())
Record.push_back(D->getNumExpansionTypes());
@@ -1682,6 +1684,8 @@ void ASTDeclWriter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
// TemplateParmPosition.
Record.push_back(D->getDepth());
Record.push_back(D->getPosition());
+ if (TypeConstraint)
+ Record.AddStmt(TypeConstraint);
if (D->isExpandedParameterPack()) {
for (unsigned I = 0, N = D->getNumExpansionTypes(); I != N; ++I) {
diff --git a/clang/test/AST/ast-dump-record-definition-data-json.cpp b/clang/test/AST/ast-dump-record-definition-data-json.cpp
index 2603eedcd81..44ec2a2f7bc 100644
--- a/clang/test/AST/ast-dump-record-definition-data-json.cpp
+++ b/clang/test/AST/ast-dump-record-definition-data-json.cpp
@@ -417,15 +417,24 @@ struct DoesNotAllowConstDefaultInit {
// CHECK-NEXT: "id": "0x{{.*}}",
// CHECK-NEXT: "kind": "TemplateTypeParmDecl",
// CHECK-NEXT: "loc": {
-// CHECK-NEXT: "offset": 193,
-// CHECK-NEXT: "col": 29,
-// CHECK-NEXT: "tokLen": 4
+// CHECK-NEXT: "offset": 197,
+// CHECK-NEXT: "col": 33,
+// CHECK-NEXT: "tokLen": 1
// CHECK-NEXT: },
// CHECK-NEXT: "range": {
-// CHECK-NEXT: "begin": {},
-// CHECK-NEXT: "end": {}
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "offset": 193,
+// CHECK-NEXT: "col": 29,
+// CHECK-NEXT: "tokLen": 4
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "offset": 197,
+// CHECK-NEXT: "col": 33,
+// CHECK-NEXT: "tokLen": 1
+// CHECK-NEXT: }
// CHECK-NEXT: },
// CHECK-NEXT: "isImplicit": true,
+// CHECK-NEXT: "name": "auto:1",
// CHECK-NEXT: "tagUsed": "class",
// CHECK-NEXT: "depth": 0,
// CHECK-NEXT: "index": 0
@@ -524,15 +533,24 @@ struct DoesNotAllowConstDefaultInit {
// CHECK-NEXT: "id": "0x{{.*}}",
// CHECK-NEXT: "kind": "TemplateTypeParmDecl",
// CHECK-NEXT: "loc": {
-// CHECK-NEXT: "offset": 193,
-// CHECK-NEXT: "col": 29,
-// CHECK-NEXT: "tokLen": 4
+// CHECK-NEXT: "offset": 197,
+// CHECK-NEXT: "col": 33,
+// CHECK-NEXT: "tokLen": 1
// CHECK-NEXT: },
// CHECK-NEXT: "range": {
-// CHECK-NEXT: "begin": {},
-// CHECK-NEXT: "end": {}
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "offset": 193,
+// CHECK-NEXT: "col": 29,
+// CHECK-NEXT: "tokLen": 4
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "offset": 197,
+// CHECK-NEXT: "col": 33,
+// CHECK-NEXT: "tokLen": 1
+// CHECK-NEXT: }
// CHECK-NEXT: },
// CHECK-NEXT: "isImplicit": true,
+// CHECK-NEXT: "name": "auto:1",
// CHECK-NEXT: "tagUsed": "class",
// CHECK-NEXT: "depth": 0,
// CHECK-NEXT: "index": 0
@@ -590,15 +608,24 @@ struct DoesNotAllowConstDefaultInit {
// CHECK-NEXT: "id": "0x{{.*}}",
// CHECK-NEXT: "kind": "TemplateTypeParmDecl",
// CHECK-NEXT: "loc": {
-// CHECK-NEXT: "offset": 193,
-// CHECK-NEXT: "col": 29,
-// CHECK-NEXT: "tokLen": 4
+// CHECK-NEXT: "offset": 197,
+// CHECK-NEXT: "col": 33,
+// CHECK-NEXT: "tokLen": 1
// CHECK-NEXT: },
// CHECK-NEXT: "range": {
-// CHECK-NEXT: "begin": {},
-// CHECK-NEXT: "end": {}
+// CHECK-NEXT: "begin": {
+// CHECK-NEXT: "offset": 193,
+// CHECK-NEXT: "col": 29,
+// CHECK-NEXT: "tokLen": 4
+// CHECK-NEXT: },
+// CHECK-NEXT: "end": {
+// CHECK-NEXT: "offset": 197,
+// CHECK-NEXT: "col": 33,
+// CHECK-NEXT: "tokLen": 1
+// CHECK-NEXT: }
// CHECK-NEXT: },
// CHECK-NEXT: "isImplicit": true,
+// CHECK-NEXT: "name": "auto:1",
// CHECK-NEXT: "tagUsed": "class",
// CHECK-NEXT: "depth": 0,
// CHECK-NEXT: "index": 0
diff --git a/clang/test/CXX/dcl/dcl.fct/p17.cpp b/clang/test/CXX/dcl/dcl.fct/p17.cpp
new file mode 100644
index 00000000000..bf19e57e796
--- /dev/null
+++ b/clang/test/CXX/dcl/dcl.fct/p17.cpp
@@ -0,0 +1,260 @@
+// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -verify %s
+template<typename T, typename U> constexpr bool is_same_v = false;
+template<typename T> constexpr bool is_same_v<T, T> = true;
+
+template<typename... T>
+struct type_list;
+
+namespace unconstrained {
+ decltype(auto) f1(auto x) { return x; }
+ static_assert(is_same_v<decltype(f1(1)), int>);
+ static_assert(is_same_v<decltype(f1('c')), char>);
+
+ decltype(auto) f2(auto &x) { return x; }
+ // expected-note@-1{{candidate function [with x:auto = int] not viable: expects an l-value for 1st argument}}
+ // expected-note@-2{{candidate function [with x:auto = char] not viable: expects an l-value for 1st argument}}
+ static_assert(is_same_v<decltype(f2(1)), int &>); // expected-error{{no matching}}
+ static_assert(is_same_v<decltype(f2('c')), char &>); // expected-error{{no matching}}
+
+ decltype(auto) f3(const auto &x) { return x; }
+ static_assert(is_same_v<decltype(f3(1)), const int &>);
+ static_assert(is_same_v<decltype(f3('c')), const char &>);
+
+ decltype(auto) f4(auto (*x)(auto y)) { return x; } // expected-error{{'auto' not allowed in function prototype}}
+
+ decltype(auto) f5(void (*x)(decltype(auto) y)) { return x; } // expected-error{{'decltype(auto)' not allowed in function prototype}}
+
+ int return_int(); void return_void(); int foo(int);
+
+ decltype(auto) f6(auto (*x)()) { return x; }
+ // expected-note@-1{{candidate template ignored: failed template argument deduction}}
+ static_assert(is_same_v<decltype(f6(return_int)), int (*)()>);
+ static_assert(is_same_v<decltype(f6(return_void)), void (*)()>);
+ using f6c1 = decltype(f6(foo)); // expected-error{{no matching}}
+
+ decltype(auto) f7(auto (*x)() -> int) { return x; }
+ // expected-note@-1{{candidate function not viable: no known conversion from 'void ()' to 'auto (*)() -> int' for 1st argument}}
+ // expected-note@-2{{candidate function not viable: no known conversion from 'int (int)' to 'auto (*)() -> int' for 1st argument}}
+ static_assert(is_same_v<decltype(f7(return_int)), int (*)()>);
+ using f7c1 = decltype(f7(return_void)); // expected-error{{no matching}}
+ using f7c2 = decltype(f7(foo)); // expected-error{{no matching}}
+ static_assert(is_same_v<decltype(&f7), int (*(*)(int (*x)()))()>);
+
+ decltype(auto) f8(auto... x) { return (x + ...); }
+ static_assert(is_same_v<decltype(f8(1, 2, 3)), int>);
+ static_assert(is_same_v<decltype(f8('c', 'd')), int>);
+ static_assert(is_same_v<decltype(f8('c', 1)), int>);
+
+ decltype(auto) f9(auto &... x) { return (x, ...); }
+ // expected-note@-1{{candidate function [with x:auto = <int (), int>] not viable: expects an l-value for 2nd argument}}
+ using f9c1 = decltype(f9(return_int, 1)); // expected-error{{no matching}}
+
+ decltype(auto) f11(decltype(auto) x) { return x; } // expected-error{{'decltype(auto)' not allowed in function prototype}}
+
+ template<typename T>
+ auto f12(auto x, T y) -> type_list<T, decltype(x)>;
+ static_assert(is_same_v<decltype(f12(1, 'c')), type_list<char, int>>);
+ static_assert(is_same_v<decltype(f12<char>(1, 'c')), type_list<char, int>>);
+
+ template<typename T>
+ auto f13(T x, auto y) -> type_list<T, decltype(y)>;
+ static_assert(is_same_v<decltype(f13(1, 'c')), type_list<int, char>>);
+ static_assert(is_same_v<decltype(f13<char>(1, 'c')), type_list<char, char>>);
+
+ template<typename T>
+ auto f14(auto y) -> type_list<T, decltype(y)>;
+ static_assert(is_same_v<decltype(f14<int>('c')), type_list<int, char>>);
+ static_assert(is_same_v<decltype(f14<int, char>('c')), type_list<int, char>>);
+
+ template<typename T, typename U>
+ auto f15(auto y, U u) -> type_list<T, U, decltype(y)>;
+ static_assert(is_same_v<decltype(f15<int>('c', nullptr)), type_list<int, decltype(nullptr), char>>);
+ static_assert(is_same_v<decltype(f15<int, decltype(nullptr)>('c', nullptr)), type_list<int, decltype(nullptr), char>>);
+
+ auto f16(auto x, auto y) -> type_list<decltype(x), decltype(y)>;
+ static_assert(is_same_v<decltype(f16('c', 1)), type_list<char, int>>);
+ static_assert(is_same_v<decltype(f16<int>('c', 1)), type_list<int, int>>);
+ static_assert(is_same_v<decltype(f16<int, char>('c', 1)), type_list<int, char>>);
+
+ void f17(auto x, auto y) requires (sizeof(x) > 1);
+ // expected-note@-1{{candidate template ignored: constraints not satisfied [with x:auto = char, y:auto = int]}}
+ // expected-note@-2{{because 'sizeof (x) > 1' (1 > 1) evaluated to false}}
+ static_assert(is_same_v<decltype(f17('c', 1)), void>);
+ // expected-error@-1{{no matching}}
+ static_assert(is_same_v<decltype(f17<int>('c', 1)), void>);
+ static_assert(is_same_v<decltype(f17<int, char>('c', 1)), void>);
+
+ void f18(auto... x) requires (sizeof...(x) == 2);
+ // expected-note@-1{{candidate template ignored: constraints not satisfied [with x:auto = <char, int, int>]}}
+ // expected-note@-2{{candidate template ignored: constraints not satisfied [with x:auto = <char>]}}
+ // expected-note@-3{{because 'sizeof...(x) == 2' (1 == 2) evaluated to false}}
+ // expected-note@-4{{because 'sizeof...(x) == 2' (3 == 2) evaluated to false}}
+ static_assert(is_same_v<decltype(f18('c')), void>);
+ // expected-error@-1{{no matching}}
+ static_assert(is_same_v<decltype(f18('c', 1)), void>);
+ static_assert(is_same_v<decltype(f18('c', 1, 2)), void>);
+ // expected-error@-1{{no matching}}
+
+ template<typename T>
+ struct S {
+ constexpr auto f1(auto x, T t) -> decltype(x + t);
+
+ template<typename U>
+ constexpr auto f2(U u, auto x, T t) -> decltype(x + u + t);
+ };
+
+ template<typename T>
+ constexpr auto S<T>::f1(auto x, T t) -> decltype(x + t) { return x + t; }
+
+ template<typename T>
+ template<typename U>
+ constexpr auto S<T>::f2(auto x, U u, T t) -> decltype(x + u + t) { return x + u + t; }
+ // expected-error@-1 {{out-of-line definition of 'f2' does not match any declaration in 'S<T>'}}
+
+ template<typename T>
+ template<typename U>
+ constexpr auto S<T>::f2(U u, auto x, T t) -> decltype(x + u + t) { return x + u + t; }
+
+ template<>
+ template<>
+ constexpr auto S<int>::f2<double>(double u, char x, int t) -> double { return 42; }
+
+ static_assert(S<char>{}.f1(1, 2) == 3);
+ static_assert(S<char>{}.f2(1, 2, '\x00') == 3);
+ static_assert(S<char>{}.f2<double>(1, 2, '\x00') == 3.);
+ static_assert(S<int>{}.f2<double>(1, '2', '\x00') == 42);
+}
+
+namespace constrained {
+ template<typename T>
+ concept C = is_same_v<T, int>;
+ // expected-note@-1 12{{because}}
+ template<typename T, typename U>
+ concept C2 = is_same_v<T, U>;
+ // expected-note@-1 12{{because}}
+
+ int i;
+ const int ci = 1;
+ char c;
+ const char cc = 'a';
+ int g(int);
+ char h(int);
+
+ void f1(C auto x);
+ // expected-note@-1 {{candidate template ignored: constraints not satisfied [with x:auto = }}
+ // expected-note@-2{{because}}
+ static_assert(is_same_v<decltype(f1(1)), void>);
+ static_assert(is_same_v<decltype(f1('a')), void>);
+ // expected-error@-1{{no matching}}
+ void f2(C auto &x);
+ // expected-note@-1 2{{candidate template ignored}} expected-note@-1 2{{because}}
+ static_assert(is_same_v<decltype(f2(i)), void>);
+ static_assert(is_same_v<decltype(f2(ci)), void>);
+ // expected-error@-1{{no matching}}
+ static_assert(is_same_v<decltype(f2(c)), void>);
+ // expected-error@-1{{no matching}}
+ void f3(const C auto &x);
+ // expected-note@-1{{candidate template ignored}} expected-note@-1{{because}}
+ static_assert(is_same_v<decltype(f3(i)), void>);
+ static_assert(is_same_v<decltype(f3(ci)), void>);
+ static_assert(is_same_v<decltype(f3(c)), void>);
+ // expected-error@-1{{no matching}}
+ void f4(C auto (*x)(C auto y)); // expected-error{{'auto' not allowed}}
+ void f5(C auto (*x)(int y));
+ // expected-note@-1{{candidate template ignored}} expected-note@-1{{because}}
+ static_assert(is_same_v<decltype(f5(g)), void>);
+ static_assert(is_same_v<decltype(f5(h)), void>);
+ // expected-error@-1{{no matching}}
+ void f6(C auto (*x)() -> int); // expected-error{{function with trailing return type must specify return type 'auto', not 'C auto'}}
+ void f7(C auto... x);
+ // expected-note@-1 2{{candidate template ignored}} expected-note@-1 2{{because}}
+ static_assert(is_same_v<decltype(f7(1, 2)), void>);
+ static_assert(is_same_v<decltype(f7(1, 'a')), void>);
+ // expected-error@-1{{no matching}}
+ static_assert(is_same_v<decltype(f7('a', 2)), void>);
+ // expected-error@-1{{no matching}}
+ void f8(C auto &... x);
+ // expected-note@-1 2{{candidate template ignored}} expected-note@-1 2{{because}}
+ static_assert(is_same_v<decltype(f8(i, i)), void>);
+ static_assert(is_same_v<decltype(f8(i, c)), void>);
+ // expected-error@-1{{no matching}}
+ static_assert(is_same_v<decltype(f8(i, i, ci)), void>);
+ // expected-error@-1{{no matching}}
+ void f9(const C auto &... x);
+ // expected-note@-1{{candidate template ignored}} expected-note@-1{{because}}
+ static_assert(is_same_v<decltype(f9(i, i)), void>);
+ static_assert(is_same_v<decltype(f9(i, c)), void>);
+ // expected-error@-1{{no matching}}
+ static_assert(is_same_v<decltype(f9(i, i, ci)), void>);
+ void f10(C decltype(auto) x);
+ auto f11 = [] (C auto x) { };
+ // expected-note@-1{{candidate template ignored}} expected-note@-1{{because}}
+ static_assert(is_same_v<decltype(f11(1)), void>);
+ static_assert(is_same_v<decltype(f11('a')), void>);
+ // expected-error@-1{{no matching}}
+
+ void f12(C2<char> auto x);
+ // expected-note@-1{{candidate template ignored}} expected-note@-1{{because}}
+ static_assert(is_same_v<decltype(f12(1)), void>);
+ // expected-error@-1{{no matching}}
+ static_assert(is_same_v<decltype(f12('a')), void>);
+ void f13(C2<char> auto &x);
+ // expected-note@-1 2{{candidate template ignored}} expected-note@-1 2{{because}}
+ static_assert(is_same_v<decltype(f13(i)), void>);
+ // expected-error@-1{{no matching}}
+ static_assert(is_same_v<decltype(f13(cc)), void>);
+ // expected-error@-1{{no matching}}
+ static_assert(is_same_v<decltype(f13(c)), void>);
+ void f14(const C2<char> auto &x);
+ // expected-note@-1{{candidate template ignored}} expected-note@-1{{because}}
+ static_assert(is_same_v<decltype(f14(i)), void>);
+ // expected-error@-1{{no matching}}
+ static_assert(is_same_v<decltype(f14(cc)), void>);
+ static_assert(is_same_v<decltype(f14(c)), void>);
+ void f15(C2<char> auto (*x)(C2<int> auto y)); // expected-error{{'auto' not allowed}}
+ void f16(C2<char> auto (*x)(int y));
+ // expected-note@-1{{candidate template ignored}} expected-note@-1{{because}}
+ static_assert(is_same_v<decltype(f16(g)), void>);
+ // expected-error@-1{{no matching}}
+ static_assert(is_same_v<decltype(f16(h)), void>);
+ void f17(C2<char> auto (*x)() -> int); // expected-error{{function with trailing return type must specify return type 'auto', not 'C2<char> auto'}}
+ void f18(C2<char> auto... x);
+ // expected-note@-1 2{{candidate template ignored}} expected-note@-1 2{{because}}
+ static_assert(is_same_v<decltype(f18('a', 'b')), void>);
+ static_assert(is_same_v<decltype(f18('a', 1)), void>);
+ // expected-error@-1{{no matching}}
+ static_assert(is_same_v<decltype(f18(2, 'a')), void>);
+ // expected-error@-1{{no matching}}
+ void f19(C2<char> auto &... x);
+ // expected-note@-1 2{{candidate template ignored}} expected-note@-1 2{{because}}
+ static_assert(is_same_v<decltype(f19(c, c)), void>);
+ static_assert(is_same_v<decltype(f19(i, c)), void>);
+ // expected-error@-1{{no matching}}
+ static_assert(is_same_v<decltype(f19(c, c, cc)), void>);
+ // expected-error@-1{{no matching}}
+ void f20(const C2<char> auto &... x);
+ // expected-note@-1{{candidate template ignored}} expected-note@-1{{because}}
+ static_assert(is_same_v<decltype(f20(c, c)), void>);
+ static_assert(is_same_v<decltype(f20(i, c)), void>);
+ // expected-error@-1{{no matching}}
+ static_assert(is_same_v<decltype(f20(c, c, cc)), void>);
+ void f21(C2<char> decltype(auto) x);
+ auto f22 = [] (C2<char> auto x) { };
+ // expected-note@-1{{candidate template ignored}} expected-note@-1{{because}}
+ static_assert(is_same_v<decltype(f22(1)), void>);
+ // expected-error@-1{{no matching}}
+ static_assert(is_same_v<decltype(f22('a')), void>);
+
+ struct S1 { S1(C auto); };
+ // expected-note@-1{{candidate template ignored}} expected-note@-1{{because}}
+ // expected-note@-2 2{{candidate constructor}}
+ static_assert(is_same_v<decltype(S1(1)), S1>);
+ static_assert(is_same_v<decltype(S1('a')), S1>);
+ // expected-error@-1{{no matching}}
+ struct S2 { S2(C2<char> auto); };
+ // expected-note@-1{{candidate template ignored}} expected-note@-1{{because}}
+ // expected-note@-2 2{{candidate constructor}}
+ static_assert(is_same_v<decltype(S2(1)), S2>);
+ // expected-error@-1{{no matching}}
+ static_assert(is_same_v<decltype(S2('a')), S2>);
+}
diff --git a/clang/test/CXX/dcl/dcl.spec/dcl.type/dcl.spec.auto/p6.cpp b/clang/test/CXX/dcl/dcl.spec/dcl.type/dcl.spec.auto/p6.cpp
new file mode 100644
index 00000000000..a4e71d341cd
--- /dev/null
+++ b/clang/test/CXX/dcl/dcl.spec/dcl.type/dcl.spec.auto/p6.cpp
@@ -0,0 +1,44 @@
+// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -verify %s
+
+template<typename T, unsigned size>
+concept LargerThan = sizeof(T) > size;
+// expected-note@-1 2{{because 'sizeof(char) > 1U' (1 > 1) evaluated to false}}
+// expected-note@-2 {{because 'sizeof(int) > 10U' (4 > 10) evaluated to false}}
+// expected-note@-3 {{because 'sizeof(int) > 4U' (4 > 4) evaluated to false}}
+
+template<typename T>
+concept Large = LargerThan<T, 1>;
+// expected-note@-1 2{{because 'LargerThan<char, 1>' evaluated to false}}
+
+namespace X {
+ template<typename T, unsigned size>
+ concept SmallerThan = sizeof(T) < size;
+ template<typename T>
+ concept Small = SmallerThan<T, 2>;
+}
+
+Large auto test1() { // expected-error{{deduced type 'char' does not satisfy 'Large'}}
+ Large auto i = 'a';
+ // expected-error@-1{{deduced type 'char' does not satisfy 'Large'}}
+ Large auto j = 10;
+ ::Large auto k = 10;
+ LargerThan<1> auto l = 10;
+ ::LargerThan<1> auto m = 10;
+ LargerThan<10> auto n = 10;
+ // expected-error@-1{{deduced type 'int' does not satisfy 'LargerThan<10>'}}
+ X::Small auto o = 'x';
+ X::SmallerThan<5> auto p = 1;
+ return 'a';
+}
+
+::Large auto test2() { return 10; }
+LargerThan<4> auto test3() { return 10; }
+// expected-error@-1{{deduced type 'int' does not satisfy 'LargerThan<4>'}}
+::LargerThan<2> auto test4() { return 10; }
+
+Large auto test5() -> void;
+// expected-error@-1{{function with trailing return type must specify return type 'auto', not 'Large auto'}}
+auto test6() -> Large auto { return 1; }
+
+X::Small auto test7() { return 'a'; }
+X::SmallerThan<5> auto test8() { return 10; } \ No newline at end of file
diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/expr.prim.lambda.closure/p3.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/expr.prim.lambda.closure/p3.cpp
index 942280e1059..0c0f820d168 100644
--- a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/expr.prim.lambda.closure/p3.cpp
+++ b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/expr.prim.lambda.closure/p3.cpp
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -verify %s
auto l1 = [] (auto x) requires (sizeof(decltype(x)) == 1) { return x; };
-// expected-note@-1{{candidate template ignored: constraints not satisfied [with $0 = int]}}
+// expected-note@-1{{candidate template ignored: constraints not satisfied [with x:auto = int]}}
// expected-note@-2{{because 'sizeof(decltype(x)) == 1' (4 == 1) evaluated to false}}
auto l1t1 = l1('a');
@@ -9,8 +9,8 @@ auto l1t2 = l1(1);
// expected-error@-1{{no matching function for call to object of type '(lambda at}}
auto l2 = [] (auto... x) requires ((sizeof(decltype(x)) >= 2) && ...) { return (x + ...); };
-// expected-note@-1{{candidate template ignored: constraints not satisfied [with $0 = <char>]}}
-// expected-note@-2{{candidate template ignored: constraints not satisfied [with $0 = <int, char>]}}
+// expected-note@-1{{candidate template ignored: constraints not satisfied [with x:auto = <char>]}}
+// expected-note@-2{{candidate template ignored: constraints not satisfied [with x:auto = <int, char>]}}
// expected-note@-3 2{{because 'sizeof(decltype(x)) >= 2' (1 >= 2) evaluated to false}}
auto l2t1 = l2('a');
diff --git a/clang/test/CXX/temp/temp.param/p10-2a.cpp b/clang/test/CXX/temp/temp.param/p10-2a.cpp
index de40f8cca5d..3d2be1a92be 100644
--- a/clang/test/CXX/temp/temp.param/p10-2a.cpp
+++ b/clang/test/CXX/temp/temp.param/p10-2a.cpp
@@ -94,6 +94,8 @@ concept OneOf = (is_same_v<T, Ts> || ...);
// expected-note@-5 {{and 'is_same_v<short, char>' evaluated to false}}
// expected-note@-6 3{{because 'is_same_v<int, char [1]>' evaluated to false}}
// expected-note@-7 3{{and 'is_same_v<int, char [2]>' evaluated to false}}
+// expected-note@-8 2{{because 'is_same_v<nullptr_t, char>' evaluated to false}}
+// expected-note@-9 2{{and 'is_same_v<nullptr_t, int>' evaluated to false}}
template<OneOf<char[1], char[2]> T, OneOf<int, long, char> U>
// expected-note@-1 2{{because 'OneOf<char, char [1], char [2]>' evaluated to false}}
@@ -114,4 +116,25 @@ using h1 = H<char[1], int>;
// expected-error@-1 {{constraints not satisfied for alias template 'H' [with Ts = <char [1], int>]}}
using h2 = H<int, int>;
// expected-error@-1 {{constraints not satisfied for alias template 'H' [with Ts = <int, int>]}}
-using h3 = H<char[1], char[2]>; \ No newline at end of file
+using h3 = H<char[1], char[2]>;
+
+template<OneOf<char, int> auto x>
+// expected-note@-1 {{because 'OneOf<decltype(nullptr), char, int>' evaluated to false}}
+using I = int;
+
+using i1 = I<1>;
+using i2 = I<'a'>;
+using i3 = I<nullptr>;
+// expected-error@-1 {{constraints not satisfied for alias template 'I' [with x = nullptr]}}
+
+template<OneOf<char, int> auto... x>
+// expected-note@-1 {{because 'OneOf<decltype(nullptr), char, int>' evaluated to false}}
+using J = int;
+
+using j1 = J<1, 'b'>;
+using j2 = J<'a', nullptr>;
+// expected-error@-1 {{constraints not satisfied for alias template 'J' [with x = <'a', nullptr>]}}
+
+template<OneOf<char, int> auto &x>
+// expected-error@-1 {{constrained placeholder types other than simple 'auto' on non-type template parameters not supported yet}}
+using K = int;
diff --git a/clang/test/Parser/cxx2a-placeholder-type-constraint.cpp b/clang/test/Parser/cxx2a-placeholder-type-constraint.cpp
new file mode 100644
index 00000000000..a1bd08827b9
--- /dev/null
+++ b/clang/test/Parser/cxx2a-placeholder-type-constraint.cpp
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -x c++ %s -verify
+
+template<typename T, typename U=void>
+concept C = true;
+
+int foo() {
+ C auto a4 = 1;
+ C<> auto a5 = 1;
+ C<int> auto a6 = 1;
+ const C auto &a7 = 1;
+ const C<> auto &a8 = 1;
+ const C<int> auto &a9 = 1;
+ C decltype(auto) a10 = 1;
+ C<> decltype(auto) a11 = 1;
+ C<int> decltype(auto) a12 = 1;
+ const C<> decltype(auto) &a13 = 1; // expected-error{{'decltype(auto)' cannot be combined with other type specifiers}}
+ // expected-error@-1{{non-const lvalue reference to type 'int' cannot bind to a temporary of type 'int'}}
+ const C<int> decltype(auto) &a14 = 1; // expected-error{{'decltype(auto)' cannot be combined with other type specifiers}}
+ // expected-error@-1{{non-const lvalue reference to type 'int' cannot bind to a temporary of type 'int'}}
+ C a15 = 1;
+ // expected-error@-1{{expected 'auto' or 'decltype(auto)' after concept name}}
+ C decltype a19 = 1;
+ // expected-error@-1{{expected '('}}
+ C decltype(1) a20 = 1;
+ // expected-error@-1{{expected 'auto' or 'decltype(auto)' after concept name}}
+} \ No newline at end of file
diff --git a/clang/test/SemaCXX/cxx1y-generic-lambdas.cpp b/clang/test/SemaCXX/cxx1y-generic-lambdas.cpp
index 087982327c7..13ab7aae6c3 100644
--- a/clang/test/SemaCXX/cxx1y-generic-lambdas.cpp
+++ b/clang/test/SemaCXX/cxx1y-generic-lambdas.cpp
@@ -181,7 +181,7 @@ int test() {
int (*fp2)(int) = [](auto b) -> int { return b; };
int (*fp3)(char) = [](auto c) -> int { return c; };
char (*fp4)(int) = [](auto d) { return d; }; //expected-error{{no viable conversion}}\
- //expected-note{{candidate function [with $0 = int]}}
+ //expected-note{{candidate function [with d:auto = int]}}
char (*fp5)(char) = [](auto e) -> int { return e; }; //expected-error{{no viable conversion}}\
//expected-note{{candidate template ignored}}
diff --git a/clang/test/SemaTemplate/ms-delayed-default-template-args.cpp b/clang/test/SemaTemplate/ms-delayed-default-template-args.cpp
index 27646487534..b2350c900e6 100644
--- a/clang/test/SemaTemplate/ms-delayed-default-template-args.cpp
+++ b/clang/test/SemaTemplate/ms-delayed-default-template-args.cpp
@@ -93,7 +93,8 @@ namespace test_undeclared_nontype_parm_arg {
// template parameter.
template <typename T> struct Bar { T x; };
-template <Bar<Xylophone> *P> // expected-error {{use of undeclared identifier 'Xylophone'}} expected-note {{declared here}}
+template <Bar<Xylophone> *P> // expected-error {{use of undeclared identifier 'Xylophone'}}
+// expected-note@-1{{template parameter is declared here}}
struct Foo { };
typedef int Xylophone;
OpenPOWER on IntegriCloud