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