/src/llvm-project/clang/lib/AST/ExprConcepts.cpp
Line | Count | Source (jump to first uncovered line) |
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, ConceptReference *Loc, |
35 | | ImplicitConceptSpecializationDecl *SpecDecl, |
36 | | const ConstraintSatisfaction *Satisfaction) |
37 | | : Expr(ConceptSpecializationExprClass, C.BoolTy, VK_PRValue, OK_Ordinary), |
38 | | ConceptRef(Loc), SpecDecl(SpecDecl), |
39 | | Satisfaction(Satisfaction |
40 | | ? ASTConstraintSatisfaction::Create(C, *Satisfaction) |
41 | 0 | : nullptr) { |
42 | 0 | setDependence(computeDependence(this, /*ValueDependent=*/!Satisfaction)); |
43 | | |
44 | | // Currently guaranteed by the fact concepts can only be at namespace-scope. |
45 | 0 | assert(!Loc->getNestedNameSpecifierLoc() || |
46 | 0 | (!Loc->getNestedNameSpecifierLoc() |
47 | 0 | .getNestedNameSpecifier() |
48 | 0 | ->isInstantiationDependent() && |
49 | 0 | !Loc->getNestedNameSpecifierLoc() |
50 | 0 | .getNestedNameSpecifier() |
51 | 0 | ->containsUnexpandedParameterPack())); |
52 | 0 | assert((!isValueDependent() || isInstantiationDependent()) && |
53 | 0 | "should not be value-dependent"); |
54 | 0 | } |
55 | | |
56 | | ConceptSpecializationExpr::ConceptSpecializationExpr(EmptyShell Empty) |
57 | 0 | : Expr(ConceptSpecializationExprClass, Empty) {} |
58 | | |
59 | | ConceptSpecializationExpr * |
60 | | ConceptSpecializationExpr::Create(const ASTContext &C, ConceptReference *Loc, |
61 | | ImplicitConceptSpecializationDecl *SpecDecl, |
62 | 0 | const ConstraintSatisfaction *Satisfaction) { |
63 | 0 | return new (C) ConceptSpecializationExpr(C, Loc, SpecDecl, Satisfaction); |
64 | 0 | } |
65 | | |
66 | | ConceptSpecializationExpr::ConceptSpecializationExpr( |
67 | | const ASTContext &C, ConceptReference *Loc, |
68 | | ImplicitConceptSpecializationDecl *SpecDecl, |
69 | | const ConstraintSatisfaction *Satisfaction, bool Dependent, |
70 | | bool ContainsUnexpandedParameterPack) |
71 | | : Expr(ConceptSpecializationExprClass, C.BoolTy, VK_PRValue, OK_Ordinary), |
72 | | ConceptRef(Loc), SpecDecl(SpecDecl), |
73 | | Satisfaction(Satisfaction |
74 | | ? ASTConstraintSatisfaction::Create(C, *Satisfaction) |
75 | 0 | : nullptr) { |
76 | 0 | ExprDependence D = ExprDependence::None; |
77 | 0 | if (!Satisfaction) |
78 | 0 | D |= ExprDependence::Value; |
79 | 0 | if (Dependent) |
80 | 0 | D |= ExprDependence::Instantiation; |
81 | 0 | if (ContainsUnexpandedParameterPack) |
82 | 0 | D |= ExprDependence::UnexpandedPack; |
83 | 0 | setDependence(D); |
84 | 0 | } |
85 | | |
86 | | ConceptSpecializationExpr * |
87 | | ConceptSpecializationExpr::Create(const ASTContext &C, ConceptReference *Loc, |
88 | | ImplicitConceptSpecializationDecl *SpecDecl, |
89 | | const ConstraintSatisfaction *Satisfaction, |
90 | | bool Dependent, |
91 | 0 | bool ContainsUnexpandedParameterPack) { |
92 | 0 | return new (C) |
93 | 0 | ConceptSpecializationExpr(C, Loc, SpecDecl, Satisfaction, Dependent, |
94 | 0 | ContainsUnexpandedParameterPack); |
95 | 0 | } |
96 | | |
97 | | const TypeConstraint * |
98 | 0 | concepts::ExprRequirement::ReturnTypeRequirement::getTypeConstraint() const { |
99 | 0 | assert(isTypeConstraint()); |
100 | 0 | auto TPL = |
101 | 0 | TypeConstraintInfo.getPointer().get<TemplateParameterList *>(); |
102 | 0 | return cast<TemplateTypeParmDecl>(TPL->getParam(0)) |
103 | 0 | ->getTypeConstraint(); |
104 | 0 | } |
105 | | |
106 | | // Search through the requirements, and see if any have a RecoveryExpr in it, |
107 | | // which means this RequiresExpr ALSO needs to be invalid. |
108 | 0 | static bool RequirementContainsError(concepts::Requirement *R) { |
109 | 0 | if (auto *ExprReq = dyn_cast<concepts::ExprRequirement>(R)) |
110 | 0 | return ExprReq->getExpr() && ExprReq->getExpr()->containsErrors(); |
111 | | |
112 | 0 | if (auto *NestedReq = dyn_cast<concepts::NestedRequirement>(R)) |
113 | 0 | return !NestedReq->hasInvalidConstraint() && |
114 | 0 | NestedReq->getConstraintExpr() && |
115 | 0 | NestedReq->getConstraintExpr()->containsErrors(); |
116 | 0 | return false; |
117 | 0 | } |
118 | | |
119 | | RequiresExpr::RequiresExpr(ASTContext &C, SourceLocation RequiresKWLoc, |
120 | | RequiresExprBodyDecl *Body, SourceLocation LParenLoc, |
121 | | ArrayRef<ParmVarDecl *> LocalParameters, |
122 | | SourceLocation RParenLoc, |
123 | | ArrayRef<concepts::Requirement *> Requirements, |
124 | | SourceLocation RBraceLoc) |
125 | | : Expr(RequiresExprClass, C.BoolTy, VK_PRValue, OK_Ordinary), |
126 | | NumLocalParameters(LocalParameters.size()), |
127 | | NumRequirements(Requirements.size()), Body(Body), LParenLoc(LParenLoc), |
128 | 0 | RParenLoc(RParenLoc), RBraceLoc(RBraceLoc) { |
129 | 0 | RequiresExprBits.IsSatisfied = false; |
130 | 0 | RequiresExprBits.RequiresKWLoc = RequiresKWLoc; |
131 | 0 | bool Dependent = false; |
132 | 0 | bool ContainsUnexpandedParameterPack = false; |
133 | 0 | for (ParmVarDecl *P : LocalParameters) { |
134 | 0 | Dependent |= P->getType()->isInstantiationDependentType(); |
135 | 0 | ContainsUnexpandedParameterPack |= |
136 | 0 | P->getType()->containsUnexpandedParameterPack(); |
137 | 0 | } |
138 | 0 | RequiresExprBits.IsSatisfied = true; |
139 | 0 | for (concepts::Requirement *R : Requirements) { |
140 | 0 | Dependent |= R->isDependent(); |
141 | 0 | ContainsUnexpandedParameterPack |= R->containsUnexpandedParameterPack(); |
142 | 0 | if (!Dependent) { |
143 | 0 | RequiresExprBits.IsSatisfied = R->isSatisfied(); |
144 | 0 | if (!RequiresExprBits.IsSatisfied) |
145 | 0 | break; |
146 | 0 | } |
147 | | |
148 | 0 | if (RequirementContainsError(R)) |
149 | 0 | setDependence(getDependence() | ExprDependence::Error); |
150 | 0 | } |
151 | 0 | std::copy(LocalParameters.begin(), LocalParameters.end(), |
152 | 0 | getTrailingObjects<ParmVarDecl *>()); |
153 | 0 | std::copy(Requirements.begin(), Requirements.end(), |
154 | 0 | getTrailingObjects<concepts::Requirement *>()); |
155 | 0 | RequiresExprBits.IsSatisfied |= Dependent; |
156 | | // FIXME: move the computing dependency logic to ComputeDependence.h |
157 | 0 | if (ContainsUnexpandedParameterPack) |
158 | 0 | setDependence(getDependence() | ExprDependence::UnexpandedPack); |
159 | | // FIXME: this is incorrect for cases where we have a non-dependent |
160 | | // requirement, but its parameters are instantiation-dependent. RequiresExpr |
161 | | // should be instantiation-dependent if it has instantiation-dependent |
162 | | // parameters. |
163 | 0 | if (Dependent) |
164 | 0 | setDependence(getDependence() | ExprDependence::ValueInstantiation); |
165 | 0 | } |
166 | | |
167 | | RequiresExpr::RequiresExpr(ASTContext &C, EmptyShell Empty, |
168 | | unsigned NumLocalParameters, |
169 | | unsigned NumRequirements) |
170 | | : Expr(RequiresExprClass, Empty), NumLocalParameters(NumLocalParameters), |
171 | 0 | NumRequirements(NumRequirements) { } |
172 | | |
173 | | RequiresExpr *RequiresExpr::Create( |
174 | | ASTContext &C, SourceLocation RequiresKWLoc, RequiresExprBodyDecl *Body, |
175 | | SourceLocation LParenLoc, ArrayRef<ParmVarDecl *> LocalParameters, |
176 | | SourceLocation RParenLoc, ArrayRef<concepts::Requirement *> Requirements, |
177 | 0 | SourceLocation RBraceLoc) { |
178 | 0 | void *Mem = |
179 | 0 | C.Allocate(totalSizeToAlloc<ParmVarDecl *, concepts::Requirement *>( |
180 | 0 | LocalParameters.size(), Requirements.size()), |
181 | 0 | alignof(RequiresExpr)); |
182 | 0 | return new (Mem) |
183 | 0 | RequiresExpr(C, RequiresKWLoc, Body, LParenLoc, LocalParameters, |
184 | 0 | RParenLoc, Requirements, RBraceLoc); |
185 | 0 | } |
186 | | |
187 | | RequiresExpr * |
188 | | RequiresExpr::Create(ASTContext &C, EmptyShell Empty, |
189 | 0 | unsigned NumLocalParameters, unsigned NumRequirements) { |
190 | 0 | void *Mem = |
191 | 0 | C.Allocate(totalSizeToAlloc<ParmVarDecl *, concepts::Requirement *>( |
192 | 0 | NumLocalParameters, NumRequirements), |
193 | 0 | alignof(RequiresExpr)); |
194 | 0 | return new (Mem) RequiresExpr(C, Empty, NumLocalParameters, NumRequirements); |
195 | 0 | } |