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: *Satisfaction) |
41 | : nullptr) { |
42 | setDependence(computeDependence(E: this, /*ValueDependent=*/!Satisfaction)); |
43 | |
44 | // Currently guaranteed by the fact concepts can only be at namespace-scope. |
45 | assert(!Loc->getNestedNameSpecifierLoc() || |
46 | (!Loc->getNestedNameSpecifierLoc() |
47 | .getNestedNameSpecifier() |
48 | ->isInstantiationDependent() && |
49 | !Loc->getNestedNameSpecifierLoc() |
50 | .getNestedNameSpecifier() |
51 | ->containsUnexpandedParameterPack())); |
52 | assert((!isValueDependent() || isInstantiationDependent()) && |
53 | "should not be value-dependent" ); |
54 | } |
55 | |
56 | ConceptSpecializationExpr::ConceptSpecializationExpr(EmptyShell Empty) |
57 | : Expr(ConceptSpecializationExprClass, Empty) {} |
58 | |
59 | ConceptSpecializationExpr * |
60 | ConceptSpecializationExpr::Create(const ASTContext &C, ConceptReference *Loc, |
61 | ImplicitConceptSpecializationDecl *SpecDecl, |
62 | const ConstraintSatisfaction *Satisfaction) { |
63 | return new (C) ConceptSpecializationExpr(C, Loc, SpecDecl, Satisfaction); |
64 | } |
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: *Satisfaction) |
75 | : nullptr) { |
76 | ExprDependence D = ExprDependence::None; |
77 | if (!Satisfaction) |
78 | D |= ExprDependence::Value; |
79 | if (Dependent) |
80 | D |= ExprDependence::Instantiation; |
81 | if (ContainsUnexpandedParameterPack) |
82 | D |= ExprDependence::UnexpandedPack; |
83 | setDependence(D); |
84 | } |
85 | |
86 | ConceptSpecializationExpr * |
87 | ConceptSpecializationExpr::Create(const ASTContext &C, ConceptReference *Loc, |
88 | ImplicitConceptSpecializationDecl *SpecDecl, |
89 | const ConstraintSatisfaction *Satisfaction, |
90 | bool Dependent, |
91 | bool ContainsUnexpandedParameterPack) { |
92 | return new (C) |
93 | ConceptSpecializationExpr(C, Loc, SpecDecl, Satisfaction, Dependent, |
94 | ContainsUnexpandedParameterPack); |
95 | } |
96 | |
97 | const TypeConstraint * |
98 | concepts::ExprRequirement::ReturnTypeRequirement::getTypeConstraint() const { |
99 | assert(isTypeConstraint()); |
100 | auto TPL = |
101 | TypeConstraintInfo.getPointer().get<TemplateParameterList *>(); |
102 | return cast<TemplateTypeParmDecl>(Val: TPL->getParam(Idx: 0)) |
103 | ->getTypeConstraint(); |
104 | } |
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 | static bool RequirementContainsError(concepts::Requirement *R) { |
109 | if (auto *ExprReq = dyn_cast<concepts::ExprRequirement>(Val: R)) |
110 | return ExprReq->getExpr() && ExprReq->getExpr()->containsErrors(); |
111 | |
112 | if (auto *NestedReq = dyn_cast<concepts::NestedRequirement>(Val: R)) |
113 | return !NestedReq->hasInvalidConstraint() && |
114 | NestedReq->getConstraintExpr() && |
115 | NestedReq->getConstraintExpr()->containsErrors(); |
116 | return false; |
117 | } |
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 | RParenLoc(RParenLoc), RBraceLoc(RBraceLoc) { |
129 | RequiresExprBits.IsSatisfied = false; |
130 | RequiresExprBits.RequiresKWLoc = RequiresKWLoc; |
131 | bool Dependent = false; |
132 | bool ContainsUnexpandedParameterPack = false; |
133 | for (ParmVarDecl *P : LocalParameters) { |
134 | Dependent |= P->getType()->isInstantiationDependentType(); |
135 | ContainsUnexpandedParameterPack |= |
136 | P->getType()->containsUnexpandedParameterPack(); |
137 | } |
138 | RequiresExprBits.IsSatisfied = true; |
139 | for (concepts::Requirement *R : Requirements) { |
140 | Dependent |= R->isDependent(); |
141 | ContainsUnexpandedParameterPack |= R->containsUnexpandedParameterPack(); |
142 | if (!Dependent) { |
143 | RequiresExprBits.IsSatisfied = R->isSatisfied(); |
144 | if (!RequiresExprBits.IsSatisfied) |
145 | break; |
146 | } |
147 | |
148 | if (RequirementContainsError(R)) |
149 | setDependence(getDependence() | ExprDependence::Error); |
150 | } |
151 | std::copy(LocalParameters.begin(), LocalParameters.end(), |
152 | getTrailingObjects<ParmVarDecl *>()); |
153 | std::copy(Requirements.begin(), Requirements.end(), |
154 | getTrailingObjects<concepts::Requirement *>()); |
155 | RequiresExprBits.IsSatisfied |= Dependent; |
156 | // FIXME: move the computing dependency logic to ComputeDependence.h |
157 | if (ContainsUnexpandedParameterPack) |
158 | 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 | if (Dependent) |
164 | setDependence(getDependence() | ExprDependence::ValueInstantiation); |
165 | } |
166 | |
167 | RequiresExpr::RequiresExpr(ASTContext &C, EmptyShell Empty, |
168 | unsigned NumLocalParameters, |
169 | unsigned NumRequirements) |
170 | : Expr(RequiresExprClass, Empty), NumLocalParameters(NumLocalParameters), |
171 | 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 | SourceLocation RBraceLoc) { |
178 | void *Mem = |
179 | C.Allocate(Size: totalSizeToAlloc<ParmVarDecl *, concepts::Requirement *>( |
180 | Counts: LocalParameters.size(), Counts: Requirements.size()), |
181 | Align: alignof(RequiresExpr)); |
182 | return new (Mem) |
183 | RequiresExpr(C, RequiresKWLoc, Body, LParenLoc, LocalParameters, |
184 | RParenLoc, Requirements, RBraceLoc); |
185 | } |
186 | |
187 | RequiresExpr * |
188 | RequiresExpr::Create(ASTContext &C, EmptyShell Empty, |
189 | unsigned NumLocalParameters, unsigned NumRequirements) { |
190 | void *Mem = |
191 | C.Allocate(Size: totalSizeToAlloc<ParmVarDecl *, concepts::Requirement *>( |
192 | Counts: NumLocalParameters, Counts: NumRequirements), |
193 | Align: alignof(RequiresExpr)); |
194 | return new (Mem) RequiresExpr(C, Empty, NumLocalParameters, NumRequirements); |
195 | } |
196 | |