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