xref: /freebsd/contrib/llvm-project/clang/lib/AST/ASTConcept.cpp (revision e64bea71c21eb42e97aa615188ba91f6cce0d36d)
1 //===--- ASTConcept.cpp - Concepts Related AST Data Structures --*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 ///
9 /// \file
10 /// \brief This file defines AST data structures related to concepts.
11 ///
12 //===----------------------------------------------------------------------===//
13 
14 #include "clang/AST/ASTConcept.h"
15 #include "clang/AST/ASTContext.h"
16 #include "clang/AST/ExprConcepts.h"
17 #include "clang/AST/PrettyPrinter.h"
18 #include "llvm/ADT/StringExtras.h"
19 
20 using namespace clang;
21 
22 static void
23 CreateUnsatisfiedConstraintRecord(const ASTContext &C,
24                                   const UnsatisfiedConstraintRecord &Detail,
25                                   UnsatisfiedConstraintRecord *TrailingObject) {
26   if (auto *E = dyn_cast<Expr *>(Detail))
27     new (TrailingObject) UnsatisfiedConstraintRecord(E);
28   else {
29     auto &SubstitutionDiagnostic =
30         *cast<std::pair<SourceLocation, StringRef> *>(Detail);
31     StringRef Message = C.backupStr(SubstitutionDiagnostic.second);
32     auto *NewSubstDiag = new (C) std::pair<SourceLocation, StringRef>(
33         SubstitutionDiagnostic.first, Message);
34     new (TrailingObject) UnsatisfiedConstraintRecord(NewSubstDiag);
35   }
36 }
37 
38 ASTConstraintSatisfaction::ASTConstraintSatisfaction(
39     const ASTContext &C, const ConstraintSatisfaction &Satisfaction)
40     : NumRecords{Satisfaction.Details.size()},
41       IsSatisfied{Satisfaction.IsSatisfied}, ContainsErrors{
42                                                  Satisfaction.ContainsErrors} {
43   for (unsigned I = 0; I < NumRecords; ++I)
44     CreateUnsatisfiedConstraintRecord(C, Satisfaction.Details[I],
45                                       getTrailingObjects() + I);
46 }
47 
48 ASTConstraintSatisfaction::ASTConstraintSatisfaction(
49     const ASTContext &C, const ASTConstraintSatisfaction &Satisfaction)
50     : NumRecords{Satisfaction.NumRecords},
51       IsSatisfied{Satisfaction.IsSatisfied},
52       ContainsErrors{Satisfaction.ContainsErrors} {
53   for (unsigned I = 0; I < NumRecords; ++I)
54     CreateUnsatisfiedConstraintRecord(C, *(Satisfaction.begin() + I),
55                                       getTrailingObjects() + I);
56 }
57 
58 ASTConstraintSatisfaction *
59 ASTConstraintSatisfaction::Create(const ASTContext &C,
60                                   const ConstraintSatisfaction &Satisfaction) {
61   std::size_t size =
62       totalSizeToAlloc<UnsatisfiedConstraintRecord>(
63           Satisfaction.Details.size());
64   void *Mem = C.Allocate(size, alignof(ASTConstraintSatisfaction));
65   return new (Mem) ASTConstraintSatisfaction(C, Satisfaction);
66 }
67 
68 ASTConstraintSatisfaction *ASTConstraintSatisfaction::Rebuild(
69     const ASTContext &C, const ASTConstraintSatisfaction &Satisfaction) {
70   std::size_t size =
71       totalSizeToAlloc<UnsatisfiedConstraintRecord>(Satisfaction.NumRecords);
72   void *Mem = C.Allocate(size, alignof(ASTConstraintSatisfaction));
73   return new (Mem) ASTConstraintSatisfaction(C, Satisfaction);
74 }
75 
76 void ConstraintSatisfaction::Profile(
77     llvm::FoldingSetNodeID &ID, const ASTContext &C,
78     const NamedDecl *ConstraintOwner, ArrayRef<TemplateArgument> TemplateArgs) {
79   ID.AddPointer(ConstraintOwner);
80   ID.AddInteger(TemplateArgs.size());
81   for (auto &Arg : TemplateArgs)
82     Arg.Profile(ID, C);
83 }
84 
85 ConceptReference *
86 ConceptReference::Create(const ASTContext &C, NestedNameSpecifierLoc NNS,
87                          SourceLocation TemplateKWLoc,
88                          DeclarationNameInfo ConceptNameInfo,
89                          NamedDecl *FoundDecl, ConceptDecl *NamedConcept,
90                          const ASTTemplateArgumentListInfo *ArgsAsWritten) {
91   return new (C) ConceptReference(NNS, TemplateKWLoc, ConceptNameInfo,
92                                   FoundDecl, NamedConcept, ArgsAsWritten);
93 }
94 
95 void ConceptReference::print(llvm::raw_ostream &OS,
96                              const PrintingPolicy &Policy) const {
97   if (NestedNameSpec)
98     NestedNameSpec.getNestedNameSpecifier()->print(OS, Policy);
99   ConceptName.printName(OS, Policy);
100   if (hasExplicitTemplateArgs()) {
101     OS << "<";
102     llvm::ListSeparator Sep(", ");
103     // FIXME: Find corresponding parameter for argument
104     for (auto &ArgLoc : ArgsAsWritten->arguments()) {
105       OS << Sep;
106       ArgLoc.getArgument().print(Policy, OS, /*IncludeType*/ false);
107     }
108     OS << ">";
109   }
110 }
111 
112 concepts::ExprRequirement::ExprRequirement(
113     Expr *E, bool IsSimple, SourceLocation NoexceptLoc,
114     ReturnTypeRequirement Req, SatisfactionStatus Status,
115     ConceptSpecializationExpr *SubstitutedConstraintExpr)
116     : Requirement(IsSimple ? RK_Simple : RK_Compound, Status == SS_Dependent,
117                   Status == SS_Dependent &&
118                       (E->containsUnexpandedParameterPack() ||
119                        Req.containsUnexpandedParameterPack()),
120                   Status == SS_Satisfied),
121       Value(E), NoexceptLoc(NoexceptLoc), TypeReq(Req),
122       SubstitutedConstraintExpr(SubstitutedConstraintExpr), Status(Status) {
123   assert((!IsSimple || (Req.isEmpty() && NoexceptLoc.isInvalid())) &&
124          "Simple requirement must not have a return type requirement or a "
125          "noexcept specification");
126   assert((Status > SS_TypeRequirementSubstitutionFailure &&
127           Req.isTypeConstraint()) == (SubstitutedConstraintExpr != nullptr));
128 }
129 
130 concepts::ExprRequirement::ExprRequirement(
131     SubstitutionDiagnostic *ExprSubstDiag, bool IsSimple,
132     SourceLocation NoexceptLoc, ReturnTypeRequirement Req)
133     : Requirement(IsSimple ? RK_Simple : RK_Compound, Req.isDependent(),
134                   Req.containsUnexpandedParameterPack(), /*IsSatisfied=*/false),
135       Value(ExprSubstDiag), NoexceptLoc(NoexceptLoc), TypeReq(Req),
136       Status(SS_ExprSubstitutionFailure) {
137   assert((!IsSimple || (Req.isEmpty() && NoexceptLoc.isInvalid())) &&
138          "Simple requirement must not have a return type requirement or a "
139          "noexcept specification");
140 }
141 
142 concepts::ExprRequirement::ReturnTypeRequirement::ReturnTypeRequirement(
143     TemplateParameterList *TPL)
144     : TypeConstraintInfo(TPL, false) {
145   assert(TPL->size() == 1);
146   const TypeConstraint *TC =
147       cast<TemplateTypeParmDecl>(TPL->getParam(0))->getTypeConstraint();
148   assert(TC &&
149          "TPL must have a template type parameter with a type constraint");
150   auto *Constraint =
151       cast<ConceptSpecializationExpr>(TC->getImmediatelyDeclaredConstraint());
152   bool Dependent =
153       Constraint->getTemplateArgsAsWritten() &&
154       TemplateSpecializationType::anyInstantiationDependentTemplateArguments(
155           Constraint->getTemplateArgsAsWritten()->arguments().drop_front(1));
156   TypeConstraintInfo.setInt(Dependent ? true : false);
157 }
158 
159 concepts::ExprRequirement::ReturnTypeRequirement::ReturnTypeRequirement(
160     TemplateParameterList *TPL, bool IsDependent)
161     : TypeConstraintInfo(TPL, IsDependent) {}
162 
163 concepts::TypeRequirement::TypeRequirement(TypeSourceInfo *T)
164     : Requirement(RK_Type, T->getType()->isInstantiationDependentType(),
165                   T->getType()->containsUnexpandedParameterPack(),
166                   // We reach this ctor with either dependent types (in which
167                   // IsSatisfied doesn't matter) or with non-dependent type in
168                   // which the existence of the type indicates satisfaction.
169                   /*IsSatisfied=*/true),
170       Value(T),
171       Status(T->getType()->isInstantiationDependentType() ? SS_Dependent
172                                                           : SS_Satisfied) {}
173