xref: /freebsd/contrib/llvm-project/clang/lib/AST/ExprConcepts.cpp (revision 5ca8e32633c4ffbbcd6762e5888b6a4ba0708c6c)
1 //===- ExprCXX.cpp - (C++) Expression AST Node Implementation -------------===//
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 // This file implements the subclesses of Expr class declared in ExprCXX.h
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "clang/AST/ExprConcepts.h"
14 #include "clang/AST/ASTConcept.h"
15 #include "clang/AST/ASTContext.h"
16 #include "clang/AST/ComputeDependence.h"
17 #include "clang/AST/Decl.h"
18 #include "clang/AST/DeclTemplate.h"
19 #include "clang/AST/DeclarationName.h"
20 #include "clang/AST/DependenceFlags.h"
21 #include "clang/AST/Expr.h"
22 #include "clang/AST/NestedNameSpecifier.h"
23 #include "clang/AST/TemplateBase.h"
24 #include "clang/AST/Type.h"
25 #include "clang/Basic/SourceLocation.h"
26 #include "llvm/Support/TrailingObjects.h"
27 #include <algorithm>
28 #include <string>
29 #include <utility>
30 
31 using namespace clang;
32 
33 ConceptSpecializationExpr::ConceptSpecializationExpr(
34     const ASTContext &C, NestedNameSpecifierLoc NNS,
35     SourceLocation TemplateKWLoc, DeclarationNameInfo ConceptNameInfo,
36     NamedDecl *FoundDecl, ConceptDecl *NamedConcept,
37     const ASTTemplateArgumentListInfo *ArgsAsWritten,
38     ImplicitConceptSpecializationDecl *SpecDecl,
39     const ConstraintSatisfaction *Satisfaction)
40     : Expr(ConceptSpecializationExprClass, C.BoolTy, VK_PRValue, OK_Ordinary),
41       ConceptReference(NNS, TemplateKWLoc, ConceptNameInfo, FoundDecl,
42                        NamedConcept, ArgsAsWritten),
43       SpecDecl(SpecDecl),
44       Satisfaction(Satisfaction
45                        ? ASTConstraintSatisfaction::Create(C, *Satisfaction)
46                        : nullptr) {
47   setDependence(computeDependence(this, /*ValueDependent=*/!Satisfaction));
48 
49   // Currently guaranteed by the fact concepts can only be at namespace-scope.
50   assert(!NestedNameSpec ||
51          (!NestedNameSpec.getNestedNameSpecifier()->isInstantiationDependent() &&
52           !NestedNameSpec.getNestedNameSpecifier()
53               ->containsUnexpandedParameterPack()));
54   assert((!isValueDependent() || isInstantiationDependent()) &&
55          "should not be value-dependent");
56 }
57 
58 ConceptSpecializationExpr::ConceptSpecializationExpr(EmptyShell Empty)
59     : Expr(ConceptSpecializationExprClass, Empty) {}
60 
61 ConceptSpecializationExpr *ConceptSpecializationExpr::Create(
62     const ASTContext &C, NestedNameSpecifierLoc NNS,
63     SourceLocation TemplateKWLoc, DeclarationNameInfo ConceptNameInfo,
64     NamedDecl *FoundDecl, ConceptDecl *NamedConcept,
65     const ASTTemplateArgumentListInfo *ArgsAsWritten,
66     ImplicitConceptSpecializationDecl *SpecDecl,
67     const ConstraintSatisfaction *Satisfaction) {
68   return new (C) ConceptSpecializationExpr(
69       C, NNS, TemplateKWLoc, ConceptNameInfo, FoundDecl, NamedConcept,
70       ArgsAsWritten, SpecDecl, Satisfaction);
71 }
72 
73 ConceptSpecializationExpr::ConceptSpecializationExpr(
74     const ASTContext &C, ConceptDecl *NamedConcept,
75     const ASTTemplateArgumentListInfo *ArgsAsWritten,
76     ImplicitConceptSpecializationDecl *SpecDecl,
77     const ConstraintSatisfaction *Satisfaction, bool Dependent,
78     bool ContainsUnexpandedParameterPack)
79     : Expr(ConceptSpecializationExprClass, C.BoolTy, VK_PRValue, OK_Ordinary),
80       ConceptReference(NestedNameSpecifierLoc(), SourceLocation(),
81                        DeclarationNameInfo(), NamedConcept, NamedConcept,
82                        ArgsAsWritten),
83       SpecDecl(SpecDecl),
84       Satisfaction(Satisfaction
85                        ? ASTConstraintSatisfaction::Create(C, *Satisfaction)
86                        : nullptr) {
87   ExprDependence D = ExprDependence::None;
88   if (!Satisfaction)
89     D |= ExprDependence::Value;
90   if (Dependent)
91     D |= ExprDependence::Instantiation;
92   if (ContainsUnexpandedParameterPack)
93     D |= ExprDependence::UnexpandedPack;
94   setDependence(D);
95 }
96 
97 ConceptSpecializationExpr *ConceptSpecializationExpr::Create(
98     const ASTContext &C, ConceptDecl *NamedConcept,
99     const ASTTemplateArgumentListInfo *ArgsAsWritten,
100     ImplicitConceptSpecializationDecl *SpecDecl,
101     const ConstraintSatisfaction *Satisfaction, bool Dependent,
102     bool ContainsUnexpandedParameterPack) {
103   return new (C) ConceptSpecializationExpr(C, NamedConcept, ArgsAsWritten,
104                                            SpecDecl, Satisfaction, Dependent,
105                                            ContainsUnexpandedParameterPack);
106 }
107 
108 const TypeConstraint *
109 concepts::ExprRequirement::ReturnTypeRequirement::getTypeConstraint() const {
110   assert(isTypeConstraint());
111   auto TPL =
112       TypeConstraintInfo.getPointer().get<TemplateParameterList *>();
113   return cast<TemplateTypeParmDecl>(TPL->getParam(0))
114       ->getTypeConstraint();
115 }
116 
117 // Search through the requirements, and see if any have a RecoveryExpr in it,
118 // which means this RequiresExpr ALSO needs to be invalid.
119 static bool RequirementContainsError(concepts::Requirement *R) {
120   if (auto *ExprReq = dyn_cast<concepts::ExprRequirement>(R))
121     return ExprReq->getExpr() && ExprReq->getExpr()->containsErrors();
122 
123   if (auto *NestedReq = dyn_cast<concepts::NestedRequirement>(R))
124     return !NestedReq->hasInvalidConstraint() &&
125            NestedReq->getConstraintExpr() &&
126            NestedReq->getConstraintExpr()->containsErrors();
127   return false;
128 }
129 
130 RequiresExpr::RequiresExpr(ASTContext &C, SourceLocation RequiresKWLoc,
131                            RequiresExprBodyDecl *Body,
132                            ArrayRef<ParmVarDecl *> LocalParameters,
133                            ArrayRef<concepts::Requirement *> Requirements,
134                            SourceLocation RBraceLoc)
135     : Expr(RequiresExprClass, C.BoolTy, VK_PRValue, OK_Ordinary),
136       NumLocalParameters(LocalParameters.size()),
137       NumRequirements(Requirements.size()), Body(Body), RBraceLoc(RBraceLoc) {
138   RequiresExprBits.IsSatisfied = false;
139   RequiresExprBits.RequiresKWLoc = RequiresKWLoc;
140   bool Dependent = false;
141   bool ContainsUnexpandedParameterPack = false;
142   for (ParmVarDecl *P : LocalParameters) {
143     Dependent |= P->getType()->isInstantiationDependentType();
144     ContainsUnexpandedParameterPack |=
145         P->getType()->containsUnexpandedParameterPack();
146   }
147   RequiresExprBits.IsSatisfied = true;
148   for (concepts::Requirement *R : Requirements) {
149     Dependent |= R->isDependent();
150     ContainsUnexpandedParameterPack |= R->containsUnexpandedParameterPack();
151     if (!Dependent) {
152       RequiresExprBits.IsSatisfied = R->isSatisfied();
153       if (!RequiresExprBits.IsSatisfied)
154         break;
155     }
156 
157     if (RequirementContainsError(R))
158       setDependence(getDependence() | ExprDependence::Error);
159   }
160   std::copy(LocalParameters.begin(), LocalParameters.end(),
161             getTrailingObjects<ParmVarDecl *>());
162   std::copy(Requirements.begin(), Requirements.end(),
163             getTrailingObjects<concepts::Requirement *>());
164   RequiresExprBits.IsSatisfied |= Dependent;
165   // FIXME: move the computing dependency logic to ComputeDependence.h
166   if (ContainsUnexpandedParameterPack)
167     setDependence(getDependence() | ExprDependence::UnexpandedPack);
168   // FIXME: this is incorrect for cases where we have a non-dependent
169   // requirement, but its parameters are instantiation-dependent. RequiresExpr
170   // should be instantiation-dependent if it has instantiation-dependent
171   // parameters.
172   if (Dependent)
173     setDependence(getDependence() | ExprDependence::ValueInstantiation);
174 }
175 
176 RequiresExpr::RequiresExpr(ASTContext &C, EmptyShell Empty,
177                            unsigned NumLocalParameters,
178                            unsigned NumRequirements)
179   : Expr(RequiresExprClass, Empty), NumLocalParameters(NumLocalParameters),
180     NumRequirements(NumRequirements) { }
181 
182 RequiresExpr *
183 RequiresExpr::Create(ASTContext &C, SourceLocation RequiresKWLoc,
184                      RequiresExprBodyDecl *Body,
185                      ArrayRef<ParmVarDecl *> LocalParameters,
186                      ArrayRef<concepts::Requirement *> Requirements,
187                      SourceLocation RBraceLoc) {
188   void *Mem =
189       C.Allocate(totalSizeToAlloc<ParmVarDecl *, concepts::Requirement *>(
190                      LocalParameters.size(), Requirements.size()),
191                  alignof(RequiresExpr));
192   return new (Mem) RequiresExpr(C, RequiresKWLoc, Body, LocalParameters,
193                                 Requirements, RBraceLoc);
194 }
195 
196 RequiresExpr *
197 RequiresExpr::Create(ASTContext &C, EmptyShell Empty,
198                      unsigned NumLocalParameters, unsigned NumRequirements) {
199   void *Mem =
200       C.Allocate(totalSizeToAlloc<ParmVarDecl *, concepts::Requirement *>(
201                      NumLocalParameters, NumRequirements),
202                  alignof(RequiresExpr));
203   return new (Mem) RequiresExpr(C, Empty, NumLocalParameters, NumRequirements);
204 }
205