Skip to content

Commit e57a9ab

Browse files
committed
[Concepts] Placeholder constraints and abbreviated templates
This patch implements P1141R2 "Yet another approach for constrained declarations". General strategy for this patch was: - Expand AutoType to include optional type-constraint, reflecting the wording and easing the integration of constraints. - Replace autos in parameter type specifiers with invented parameters in GetTypeSpecTypeForDeclarator, using the same logic previously used for generic lambdas, now unified with abbreviated templates, by: - Tracking the template parameter lists in the Declarator object - Tracking the template parameter depth before parsing function declarators (at which point we can match template parameters against scope specifiers to know if we have an explicit template parameter list to append invented parameters to or not). - When encountering an AutoType in a parameter context we check a stack of InventedTemplateParameterInfo structures that contain the info required to create and accumulate invented template parameters (fields that were already present in LambdaScopeInfo, which now inherits from this class and is looked up when an auto is encountered in a lambda context). Resubmit after incorrect check in NonTypeTemplateParmDecl broke lldb. Differential Revision: https://reviews.llvm.org/D65042
1 parent 0957233 commit e57a9ab

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+1869
-362
lines changed

Diff for: clang/include/clang/AST/ASTContext.h

+5-2
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ class AtomicExpr;
8888
class BlockExpr;
8989
class BuiltinTemplateDecl;
9090
class CharUnits;
91+
class ConceptDecl;
9192
class CXXABI;
9293
class CXXConstructorDecl;
9394
class CXXMethodDecl;
@@ -211,7 +212,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
211212
mutable llvm::FoldingSet<ObjCObjectPointerType> ObjCObjectPointerTypes;
212213
mutable llvm::FoldingSet<DependentUnaryTransformType>
213214
DependentUnaryTransformTypes;
214-
mutable llvm::FoldingSet<AutoType> AutoTypes;
215+
mutable llvm::ContextualFoldingSet<AutoType, ASTContext&> AutoTypes;
215216
mutable llvm::FoldingSet<DeducedTemplateSpecializationType>
216217
DeducedTemplateSpecializationTypes;
217218
mutable llvm::FoldingSet<AtomicType> AtomicTypes;
@@ -1542,7 +1543,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
15421543

15431544
/// C++11 deduced auto type.
15441545
QualType getAutoType(QualType DeducedType, AutoTypeKeyword Keyword,
1545-
bool IsDependent, bool IsPack = false) const;
1546+
bool IsDependent, bool IsPack = false,
1547+
ConceptDecl *TypeConstraintConcept = nullptr,
1548+
ArrayRef<TemplateArgument> TypeConstraintArgs ={}) const;
15461549

15471550
/// C++11 deduction pattern for 'auto' type.
15481551
QualType getAutoDeductType() const;

Diff for: clang/include/clang/AST/ASTNodeTraverser.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -548,8 +548,8 @@ class ASTNodeTraverser
548548
}
549549

550550
void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D) {
551-
if (const auto *TC = D->getPlaceholderTypeConstraint())
552-
Visit(TC->getImmediatelyDeclaredConstraint());
551+
if (const auto *E = D->getPlaceholderTypeConstraint())
552+
Visit(E);
553553
if (D->hasDefaultArgument())
554554
Visit(D->getDefaultArgument(), SourceRange(),
555555
D->getDefaultArgStorage().getInheritedFrom(),

Diff for: clang/include/clang/AST/DeclTemplate.h

+29-14
Original file line numberDiff line numberDiff line change
@@ -1102,6 +1102,17 @@ class FunctionTemplateDecl : public RedeclarableTemplateDecl {
11021102
/// template.
11031103
ArrayRef<TemplateArgument> getInjectedTemplateArgs();
11041104

1105+
/// Return whether this function template is an abbreviated function template,
1106+
/// e.g. `void foo(auto x)` or `template<typename T> void foo(auto x)`
1107+
bool isAbbreviated() const {
1108+
// Since the invented template parameters generated from 'auto' parameters
1109+
// are either appended to the end of the explicit template parameter list or
1110+
// form a new template paramter list, we can simply observe the last
1111+
// parameter to determine if such a thing happened.
1112+
const TemplateParameterList *TPL = getTemplateParameters();
1113+
return TPL->getParam(TPL->size() - 1)->isImplicit();
1114+
}
1115+
11051116
/// Merge \p Prev with our RedeclarableTemplateDecl::Common.
11061117
void mergePrevDecl(FunctionTemplateDecl *Prev);
11071118

@@ -1215,7 +1226,6 @@ class TemplateTypeParmDecl final : public TypeDecl,
12151226
bool ParameterPack,
12161227
bool HasTypeConstraint = false,
12171228
Optional<unsigned> NumExpanded = None);
1218-
12191229
static TemplateTypeParmDecl *CreateDeserialized(const ASTContext &C,
12201230
unsigned ID);
12211231
static TemplateTypeParmDecl *CreateDeserialized(const ASTContext &C,
@@ -1374,7 +1384,8 @@ class NonTypeTemplateParmDecl final
13741384
: public DeclaratorDecl,
13751385
protected TemplateParmPosition,
13761386
private llvm::TrailingObjects<NonTypeTemplateParmDecl,
1377-
std::pair<QualType, TypeSourceInfo *>> {
1387+
std::pair<QualType, TypeSourceInfo *>,
1388+
Expr *> {
13781389
friend class ASTDeclReader;
13791390
friend TrailingObjects;
13801391

@@ -1429,10 +1440,12 @@ class NonTypeTemplateParmDecl final
14291440
ArrayRef<TypeSourceInfo *> ExpandedTInfos);
14301441

14311442
static NonTypeTemplateParmDecl *CreateDeserialized(ASTContext &C,
1432-
unsigned ID);
1443+
unsigned ID,
1444+
bool HasTypeConstraint);
14331445
static NonTypeTemplateParmDecl *CreateDeserialized(ASTContext &C,
14341446
unsigned ID,
1435-
unsigned NumExpandedTypes);
1447+
unsigned NumExpandedTypes,
1448+
bool HasTypeConstraint);
14361449

14371450
using TemplateParmPosition::getDepth;
14381451
using TemplateParmPosition::setDepth;
@@ -1543,20 +1556,22 @@ class NonTypeTemplateParmDecl final
15431556
return TypesAndInfos[I].second;
15441557
}
15451558

1546-
/// Return the type-constraint in the placeholder type of this non-type
1559+
/// Return the constraint introduced by the placeholder type of this non-type
15471560
/// template parameter (if any).
1548-
TypeConstraint *getPlaceholderTypeConstraint() const {
1549-
// TODO: Concepts: Implement once we have actual placeholders with type
1550-
// constraints.
1551-
return nullptr;
1561+
Expr *getPlaceholderTypeConstraint() const {
1562+
return hasPlaceholderTypeConstraint() ? *getTrailingObjects<Expr *>() :
1563+
nullptr;
1564+
}
1565+
1566+
void setPlaceholderTypeConstraint(Expr *E) {
1567+
*getTrailingObjects<Expr *>() = E;
15521568
}
15531569

15541570
/// Determine whether this non-type template parameter's type has a
15551571
/// placeholder with a type-constraint.
15561572
bool hasPlaceholderTypeConstraint() const {
1557-
// TODO: Concepts: Implement once we have actual placeholders with type
1558-
// constraints.
1559-
return false;
1573+
auto *AT = getType()->getContainedAutoType();
1574+
return AT && AT->isConstrained();
15601575
}
15611576

15621577
/// \brief Get the associated-constraints of this template parameter.
@@ -1566,8 +1581,8 @@ class NonTypeTemplateParmDecl final
15661581
/// Use this instead of getPlaceholderImmediatelyDeclaredConstraint for
15671582
/// concepts APIs that accept an ArrayRef of constraint expressions.
15681583
void getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const {
1569-
if (TypeConstraint *TC = getPlaceholderTypeConstraint())
1570-
AC.push_back(TC->getImmediatelyDeclaredConstraint());
1584+
if (Expr *E = getPlaceholderTypeConstraint())
1585+
AC.push_back(E);
15711586
}
15721587

15731588
// Implement isa/cast/dyncast/etc.

Diff for: clang/include/clang/AST/PropertiesBase.td

+2
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@ def DeclRef : RefPropertyType<"Decl"> { let ConstWhenWriting = 1; }
9999
SubclassPropertyType<"TagDecl", DeclRef>;
100100
def TemplateDeclRef :
101101
SubclassPropertyType<"TemplateDecl", DeclRef>;
102+
def ConceptDeclRef :
103+
SubclassPropertyType<"ConceptDecl", DeclRef>;
102104
def TemplateTypeParmDeclRef :
103105
SubclassPropertyType<"TemplateTypeParmDecl", DeclRef>;
104106
def TemplateTemplateParmDeclRef :

Diff for: clang/include/clang/AST/RecursiveASTVisitor.h

+13-1
Original file line numberDiff line numberDiff line change
@@ -1040,7 +1040,13 @@ DEF_TRAVERSE_TYPE(UnaryTransformType, {
10401040
TRY_TO(TraverseType(T->getUnderlyingType()));
10411041
})
10421042

1043-
DEF_TRAVERSE_TYPE(AutoType, { TRY_TO(TraverseType(T->getDeducedType())); })
1043+
DEF_TRAVERSE_TYPE(AutoType, {
1044+
TRY_TO(TraverseType(T->getDeducedType()));
1045+
if (T->isConstrained()) {
1046+
TRY_TO(TraverseDecl(T->getTypeConstraintConcept()));
1047+
TRY_TO(TraverseTemplateArguments(T->getArgs(), T->getNumArgs()));
1048+
}
1049+
})
10441050
DEF_TRAVERSE_TYPE(DeducedTemplateSpecializationType, {
10451051
TRY_TO(TraverseTemplateName(T->getTemplateName()));
10461052
TRY_TO(TraverseType(T->getDeducedType()));
@@ -1287,6 +1293,12 @@ DEF_TRAVERSE_TYPELOC(UnaryTransformType, {
12871293

12881294
DEF_TRAVERSE_TYPELOC(AutoType, {
12891295
TRY_TO(TraverseType(TL.getTypePtr()->getDeducedType()));
1296+
if (TL.isConstrained()) {
1297+
TRY_TO(TraverseNestedNameSpecifierLoc(TL.getNestedNameSpecifierLoc()));
1298+
TRY_TO(TraverseDeclarationNameInfo(TL.getConceptNameInfo()));
1299+
for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I)
1300+
TRY_TO(TraverseTemplateArgumentLoc(TL.getArgLoc(I)));
1301+
}
12901302
})
12911303

12921304
DEF_TRAVERSE_TYPELOC(DeducedTemplateSpecializationType, {

Diff for: clang/include/clang/AST/TemplateBase.h

+6-1
Original file line numberDiff line numberDiff line change
@@ -637,7 +637,7 @@ struct ASTTemplateArgumentListInfo final
637637
}
638638

639639
static const ASTTemplateArgumentListInfo *
640-
Create(ASTContext &C, const TemplateArgumentListInfo &List);
640+
Create(const ASTContext &C, const TemplateArgumentListInfo &List);
641641
};
642642

643643
/// Represents an explicit template argument list in C++, e.g.,
@@ -702,6 +702,11 @@ inline const TemplateArgument &
702702
return getArgs()[Idx];
703703
}
704704

705+
inline const TemplateArgument &AutoType::getArg(unsigned Idx) const {
706+
assert(Idx < getNumArgs() && "Template argument out of range");
707+
return getArgs()[Idx];
708+
}
709+
705710
} // namespace clang
706711

707712
#endif // LLVM_CLANG_AST_TEMPLATEBASE_H

Diff for: clang/include/clang/AST/Type.h

+56-18
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ namespace clang {
5858

5959
class ExtQuals;
6060
class QualType;
61+
class ConceptDecl;
6162
class TagDecl;
6263
class Type;
6364

@@ -1683,6 +1684,15 @@ class alignas(8) Type : public ExtQualsTypeCommonBase {
16831684
/// Was this placeholder type spelled as 'auto', 'decltype(auto)',
16841685
/// or '__auto_type'? AutoTypeKeyword value.
16851686
unsigned Keyword : 2;
1687+
1688+
/// The number of template arguments in the type-constraints, which is
1689+
/// expected to be able to hold at least 1024 according to [implimits].
1690+
/// However as this limit is somewhat easy to hit with template
1691+
/// metaprogramming we'd prefer to keep it as large as possible.
1692+
/// At the moment it has been left as a non-bitfield since this type
1693+
/// safely fits in 64 bits as an unsigned, so there is no reason to
1694+
/// introduce the performance impact of a bitfield.
1695+
unsigned NumArgs;
16861696
};
16871697

16881698
class SubstTemplateTypeParmPackTypeBitfields {
@@ -4814,8 +4824,7 @@ class SubstTemplateTypeParmPackType : public Type, public llvm::FoldingSetNode {
48144824

48154825
/// Common base class for placeholders for types that get replaced by
48164826
/// placeholder type deduction: C++11 auto, C++14 decltype(auto), C++17 deduced
4817-
/// class template types, and (eventually) constrained type names from the C++
4818-
/// Concepts TS.
4827+
/// class template types, and constrained type names.
48194828
///
48204829
/// These types are usually a placeholder for a deduced type. However, before
48214830
/// the initializer is attached, or (usually) if the initializer is
@@ -4860,18 +4869,50 @@ class DeducedType : public Type {
48604869
}
48614870
};
48624871

4863-
/// Represents a C++11 auto or C++14 decltype(auto) type.
4864-
class AutoType : public DeducedType, public llvm::FoldingSetNode {
4872+
/// Represents a C++11 auto or C++14 decltype(auto) type, possibly constrained
4873+
/// by a type-constraint.
4874+
class alignas(8) AutoType : public DeducedType, public llvm::FoldingSetNode {
48654875
friend class ASTContext; // ASTContext creates these
48664876

4877+
ConceptDecl *TypeConstraintConcept;
4878+
48674879
AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword,
4868-
bool IsDeducedAsDependent, bool IsDeducedAsPack)
4869-
: DeducedType(Auto, DeducedAsType, IsDeducedAsDependent,
4870-
IsDeducedAsDependent, IsDeducedAsPack) {
4871-
AutoTypeBits.Keyword = (unsigned)Keyword;
4880+
bool IsDeducedAsDependent, bool IsDeducedAsPack, ConceptDecl *CD,
4881+
ArrayRef<TemplateArgument> TypeConstraintArgs);
4882+
4883+
const TemplateArgument *getArgBuffer() const {
4884+
return reinterpret_cast<const TemplateArgument*>(this+1);
4885+
}
4886+
4887+
TemplateArgument *getArgBuffer() {
4888+
return reinterpret_cast<TemplateArgument*>(this+1);
48724889
}
48734890

48744891
public:
4892+
/// Retrieve the template arguments.
4893+
const TemplateArgument *getArgs() const {
4894+
return getArgBuffer();
4895+
}
4896+
4897+
/// Retrieve the number of template arguments.
4898+
unsigned getNumArgs() const {
4899+
return AutoTypeBits.NumArgs;
4900+
}
4901+
4902+
const TemplateArgument &getArg(unsigned Idx) const; // in TemplateBase.h
4903+
4904+
ArrayRef<TemplateArgument> getTypeConstraintArguments() const {
4905+
return {getArgs(), getNumArgs()};
4906+
}
4907+
4908+
ConceptDecl *getTypeConstraintConcept() const {
4909+
return TypeConstraintConcept;
4910+
}
4911+
4912+
bool isConstrained() const {
4913+
return TypeConstraintConcept != nullptr;
4914+
}
4915+
48754916
bool isDecltypeAuto() const {
48764917
return getKeyword() == AutoTypeKeyword::DecltypeAuto;
48774918
}
@@ -4880,18 +4921,15 @@ class AutoType : public DeducedType, public llvm::FoldingSetNode {
48804921
return (AutoTypeKeyword)AutoTypeBits.Keyword;
48814922
}
48824923

4883-
void Profile(llvm::FoldingSetNodeID &ID) {
4884-
Profile(ID, getDeducedType(), getKeyword(), isDependentType(),
4885-
containsUnexpandedParameterPack());
4924+
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) {
4925+
Profile(ID, Context, getDeducedType(), getKeyword(), isDependentType(),
4926+
getTypeConstraintConcept(), getTypeConstraintArguments());
48864927
}
48874928

4888-
static void Profile(llvm::FoldingSetNodeID &ID, QualType Deduced,
4889-
AutoTypeKeyword Keyword, bool IsDependent, bool IsPack) {
4890-
ID.AddPointer(Deduced.getAsOpaquePtr());
4891-
ID.AddInteger((unsigned)Keyword);
4892-
ID.AddBoolean(IsDependent);
4893-
ID.AddBoolean(IsPack);
4894-
}
4929+
static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
4930+
QualType Deduced, AutoTypeKeyword Keyword,
4931+
bool IsDependent, ConceptDecl *CD,
4932+
ArrayRef<TemplateArgument> Arguments);
48954933

48964934
static bool classof(const Type *T) {
48974935
return T->getTypeClass() == Auto;

0 commit comments

Comments
 (0)