Skip to content

Commit df061c3

Browse files
committed
[Concepts] Constrained partial specializations and function overloads.
Added support for constraint satisfaction checking and partial ordering of constraints in constrained partial specialization and function template overloads. Re-commit after fixing another crash (added regression test). Differential Revision: https://reviews.llvm.org/D41910
1 parent 1562511 commit df061c3

18 files changed

+1026
-102
lines changed

clang/include/clang/AST/DeclTemplate.h

100644100755
Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -793,9 +793,10 @@ class RedeclarableTemplateDecl : public TemplateDecl,
793793

794794
void loadLazySpecializationsImpl() const;
795795

796-
template <class EntryType> typename SpecEntryTraits<EntryType>::DeclType*
796+
template <class EntryType, typename ...ProfileArguments>
797+
typename SpecEntryTraits<EntryType>::DeclType*
797798
findSpecializationImpl(llvm::FoldingSetVector<EntryType> &Specs,
798-
ArrayRef<TemplateArgument> Args, void *&InsertPos);
799+
void *&InsertPos, ProfileArguments &&...ProfileArgs);
799800

800801
template <class Derived, class EntryType>
801802
void addSpecializationImpl(llvm::FoldingSetVector<EntryType> &Specs,
@@ -2056,7 +2057,14 @@ class ClassTemplatePartialSpecializationDecl
20562057
->getInjectedSpecializationType();
20572058
}
20582059

2059-
// FIXME: Add Profile support!
2060+
void Profile(llvm::FoldingSetNodeID &ID) const {
2061+
Profile(ID, getTemplateArgs().asArray(), getTemplateParameters(),
2062+
getASTContext());
2063+
}
2064+
2065+
static void
2066+
Profile(llvm::FoldingSetNodeID &ID, ArrayRef<TemplateArgument> TemplateArgs,
2067+
TemplateParameterList *TPL, ASTContext &Context);
20602068

20612069
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
20622070

@@ -2180,7 +2188,8 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl {
21802188
/// Return the partial specialization with the provided arguments if it
21812189
/// exists, otherwise return the insertion point.
21822190
ClassTemplatePartialSpecializationDecl *
2183-
findPartialSpecialization(ArrayRef<TemplateArgument> Args, void *&InsertPos);
2191+
findPartialSpecialization(ArrayRef<TemplateArgument> Args,
2192+
TemplateParameterList *TPL, void *&InsertPos);
21842193

21852194
/// Insert the specified partial specialization knowing that it is not
21862195
/// already in. InsertPos must be obtained from findPartialSpecialization.
@@ -2880,6 +2889,15 @@ class VarTemplatePartialSpecializationDecl
28802889
return First->InstantiatedFromMember.setInt(true);
28812890
}
28822891

2892+
void Profile(llvm::FoldingSetNodeID &ID) const {
2893+
Profile(ID, getTemplateArgs().asArray(), getTemplateParameters(),
2894+
getASTContext());
2895+
}
2896+
2897+
static void
2898+
Profile(llvm::FoldingSetNodeID &ID, ArrayRef<TemplateArgument> TemplateArgs,
2899+
TemplateParameterList *TPL, ASTContext &Context);
2900+
28832901
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
28842902

28852903
static bool classofKind(Kind K) {
@@ -2998,7 +3016,8 @@ class VarTemplateDecl : public RedeclarableTemplateDecl {
29983016
/// Return the partial specialization with the provided arguments if it
29993017
/// exists, otherwise return the insertion point.
30003018
VarTemplatePartialSpecializationDecl *
3001-
findPartialSpecialization(ArrayRef<TemplateArgument> Args, void *&InsertPos);
3019+
findPartialSpecialization(ArrayRef<TemplateArgument> Args,
3020+
TemplateParameterList *TPL, void *&InsertPos);
30023021

30033022
/// Insert the specified partial specialization knowing that it is not
30043023
/// already in. InsertPos must be obtained from findPartialSpecialization.

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2597,11 +2597,6 @@ def note_single_arg_concept_specialization_constraint_evaluated_to_false : Note<
25972597
"%select{and |because }0%1 does not satisfy %2">;
25982598
def note_atomic_constraint_evaluated_to_false_elaborated : Note<
25992599
"%select{and |because }0'%1' (%2 %3 %4) evaluated to false">;
2600-
def err_could_not_normalize_ill_formed_constraint : Error<
2601-
"required expansion of concept specialization %0 failed, substituted "
2602-
"expression would be illegal">;
2603-
def note_could_not_normalize_ill_formed_constraint_reason : Note<
2604-
"because: %0">;
26052600

26062601
def err_template_different_requires_clause : Error<
26072602
"requires clause differs in template redeclaration">;
@@ -4605,6 +4600,11 @@ def note_checking_constraints_for_class_spec_id_here : Note<
46054600
"specialization '%0' required here">;
46064601
def note_constraint_substitution_here : Note<
46074602
"while substituting template arguments into constraint expression here">;
4603+
def note_constraint_normalization_here : Note<
4604+
"while calculating associated constraint of template '%0' here">;
4605+
def note_parameter_mapping_substitution_here : Note<
4606+
"while substituting into concept arguments here; substitution failures not "
4607+
"allowed in concept arguments">;
46084608
def note_instantiation_contexts_suppressed : Note<
46094609
"(skipping %0 context%s0 in backtrace; use -ftemplate-backtrace-limit=0 to "
46104610
"see all)">;
@@ -4768,8 +4768,9 @@ def note_template_declared_here : Note<
47684768
"%select{function template|class template|variable template"
47694769
"|type alias template|template template parameter}0 "
47704770
"%1 declared here">;
4771-
def err_alias_template_expansion_into_fixed_list : Error<
4772-
"pack expansion used as argument for non-pack parameter of alias template">;
4771+
def err_template_expansion_into_fixed_list : Error<
4772+
"pack expansion used as argument for non-pack parameter of %select{alias "
4773+
"template|concept}0">;
47734774
def note_parameter_type : Note<
47744775
"parameter of type %0 is declared here">;
47754776

clang/include/clang/Sema/Sema.h

100644100755
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6171,6 +6171,25 @@ class Sema final {
61716171
/// A diagnostic is emitted if it is not, and false is returned.
61726172
bool CheckConstraintExpression(Expr *CE);
61736173

6174+
private:
6175+
/// \brief Caches pairs of template-like decls whose associated constraints
6176+
/// were checked for subsumption and whether or not the first's constraints
6177+
/// did in fact subsume the second's.
6178+
llvm::DenseMap<std::pair<NamedDecl *, NamedDecl *>, bool> SubsumptionCache;
6179+
6180+
public:
6181+
/// \brief Check whether the given declaration's associated constraints are
6182+
/// at least as constrained than another declaration's according to the
6183+
/// partial ordering of constraints.
6184+
///
6185+
/// \param Result If no error occurred, receives the result of true if D1 is
6186+
/// at least constrained than D2, and false otherwise.
6187+
///
6188+
/// \returns true if an error occurred, false otherwise.
6189+
bool IsAtLeastAsConstrained(NamedDecl *D1, ArrayRef<const Expr *> AC1,
6190+
NamedDecl *D2, ArrayRef<const Expr *> AC2,
6191+
bool &Result);
6192+
61746193
/// \brief Check whether the given list of constraint expressions are
61756194
/// satisfied (as if in a 'conjunction') given template arguments.
61766195
/// \param ConstraintExprs a list of constraint expressions, treated as if
@@ -6249,6 +6268,10 @@ class Sema final {
62496268
void DiagnoseUnsatisfiedIllFormedConstraint(SourceLocation DiagnosticLocation,
62506269
StringRef Diagnostic);
62516270

6271+
void
6272+
DiagnoseRedeclarationConstraintMismatch(const TemplateParameterList *Old,
6273+
const TemplateParameterList *New);
6274+
62526275
// ParseObjCStringLiteral - Parse Objective-C string literals.
62536276
ExprResult ParseObjCStringLiteral(SourceLocation *AtLocs,
62546277
ArrayRef<Expr *> Strings);
@@ -6888,6 +6911,12 @@ class Sema final {
68886911
QualType NTTPType,
68896912
SourceLocation Loc);
68906913

6914+
/// Get a template argument mapping the given template parameter to itself,
6915+
/// e.g. for X in \c template<int X>, this would return an expression template
6916+
/// argument referencing X.
6917+
TemplateArgumentLoc getIdentityTemplateArgumentLoc(Decl *Param,
6918+
SourceLocation Location);
6919+
68916920
void translateTemplateArguments(const ASTTemplateArgsPtr &In,
68926921
TemplateArgumentListInfo &Out);
68936922

@@ -7786,6 +7815,9 @@ class Sema final {
77867815
bool isTemplateTemplateParameterAtLeastAsSpecializedAs(
77877816
TemplateParameterList *P, TemplateDecl *AArg, SourceLocation Loc);
77887817

7818+
void MarkUsedTemplateParameters(const Expr *E, bool OnlyDeduced,
7819+
unsigned Depth, llvm::SmallBitVector &Used);
7820+
77897821
void MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs,
77907822
bool OnlyDeduced,
77917823
unsigned Depth,
@@ -7879,6 +7911,13 @@ class Sema final {
78797911
// We are substituting template arguments into a constraint expression.
78807912
ConstraintSubstitution,
78817913

7914+
// We are normalizing a constraint expression.
7915+
ConstraintNormalization,
7916+
7917+
// We are substituting into the parameter mapping of an atomic constraint
7918+
// during normalization.
7919+
ParameterMappingSubstitution,
7920+
78827921
/// We are rewriting a comparison operator in terms of an operator<=>.
78837922
RewritingOperatorAsSpaceship,
78847923

@@ -8160,6 +8199,19 @@ class Sema final {
81608199
sema::TemplateDeductionInfo &DeductionInfo,
81618200
SourceRange InstantiationRange);
81628201

8202+
struct ConstraintNormalization {};
8203+
/// \brief Note that we are normalizing a constraint expression.
8204+
InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
8205+
ConstraintNormalization, NamedDecl *Template,
8206+
SourceRange InstantiationRange);
8207+
8208+
struct ParameterMappingSubstitution {};
8209+
/// \brief Note that we are subtituting into the parameter mapping of an
8210+
/// atomic constraint during constraint normalization.
8211+
InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
8212+
ParameterMappingSubstitution, NamedDecl *Template,
8213+
SourceRange InstantiationRange);
8214+
81638215
/// Note that we have finished instantiating this template.
81648216
void Clear();
81658217

@@ -8493,6 +8545,12 @@ class Sema final {
84938545
SubstTemplateParams(TemplateParameterList *Params, DeclContext *Owner,
84948546
const MultiLevelTemplateArgumentList &TemplateArgs);
84958547

8548+
bool
8549+
SubstTemplateArguments(ArrayRef<TemplateArgumentLoc> Args,
8550+
const MultiLevelTemplateArgumentList &TemplateArgs,
8551+
TemplateArgumentListInfo &Outputs);
8552+
8553+
84968554
Decl *SubstDecl(Decl *D, DeclContext *Owner,
84978555
const MultiLevelTemplateArgumentList &TemplateArgs);
84988556

clang/lib/AST/ASTImporter.cpp

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5305,16 +5305,25 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl(
53055305
if (Error Err = ImportTemplateArguments(
53065306
D->getTemplateArgs().data(), D->getTemplateArgs().size(), TemplateArgs))
53075307
return std::move(Err);
5308-
5309-
// Try to find an existing specialization with these template arguments.
5308+
// Try to find an existing specialization with these template arguments and
5309+
// template parameter list.
53105310
void *InsertPos = nullptr;
53115311
ClassTemplateSpecializationDecl *PrevDecl = nullptr;
53125312
ClassTemplatePartialSpecializationDecl *PartialSpec =
53135313
dyn_cast<ClassTemplatePartialSpecializationDecl>(D);
5314-
if (PartialSpec)
5315-
PrevDecl =
5316-
ClassTemplate->findPartialSpecialization(TemplateArgs, InsertPos);
5317-
else
5314+
5315+
// Import template parameters.
5316+
TemplateParameterList *ToTPList = nullptr;
5317+
5318+
if (PartialSpec) {
5319+
auto ToTPListOrErr = import(PartialSpec->getTemplateParameters());
5320+
if (!ToTPListOrErr)
5321+
return ToTPListOrErr.takeError();
5322+
ToTPList = *ToTPListOrErr;
5323+
PrevDecl = ClassTemplate->findPartialSpecialization(TemplateArgs,
5324+
*ToTPListOrErr,
5325+
InsertPos);
5326+
} else
53185327
PrevDecl = ClassTemplate->findSpecialization(TemplateArgs, InsertPos);
53195328

53205329
if (PrevDecl) {
@@ -5373,24 +5382,21 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl(
53735382
return std::move(Err);
53745383
CanonInjType = CanonInjType.getCanonicalType();
53755384

5376-
auto ToTPListOrErr = import(PartialSpec->getTemplateParameters());
5377-
if (!ToTPListOrErr)
5378-
return ToTPListOrErr.takeError();
5379-
53805385
if (GetImportedOrCreateDecl<ClassTemplatePartialSpecializationDecl>(
53815386
D2, D, Importer.getToContext(), D->getTagKind(), DC,
5382-
*BeginLocOrErr, *IdLocOrErr, *ToTPListOrErr, ClassTemplate,
5387+
*BeginLocOrErr, *IdLocOrErr, ToTPList, ClassTemplate,
53835388
llvm::makeArrayRef(TemplateArgs.data(), TemplateArgs.size()),
53845389
ToTAInfo, CanonInjType,
53855390
cast_or_null<ClassTemplatePartialSpecializationDecl>(PrevDecl)))
53865391
return D2;
53875392

53885393
// Update InsertPos, because preceding import calls may have invalidated
53895394
// it by adding new specializations.
5390-
if (!ClassTemplate->findPartialSpecialization(TemplateArgs, InsertPos))
5395+
auto *PartSpec2 = cast<ClassTemplatePartialSpecializationDecl>(D2);
5396+
if (!ClassTemplate->findPartialSpecialization(TemplateArgs, ToTPList,
5397+
InsertPos))
53915398
// Add this partial specialization to the class template.
5392-
ClassTemplate->AddPartialSpecialization(
5393-
cast<ClassTemplatePartialSpecializationDecl>(D2), InsertPos);
5399+
ClassTemplate->AddPartialSpecialization(PartSpec2, InsertPos);
53945400

53955401
} else { // Not a partial specialization.
53965402
if (GetImportedOrCreateDecl(

0 commit comments

Comments
 (0)