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
ConceptSpecializationExpr(const ASTContext & C,ConceptReference * Loc,ImplicitConceptSpecializationDecl * SpecDecl,const ConstraintSatisfaction * Satisfaction)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)
37 : nullptr) {
38 setDependence(computeDependence(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
ConceptSpecializationExpr(EmptyShell Empty)52 ConceptSpecializationExpr::ConceptSpecializationExpr(EmptyShell Empty)
53 : Expr(ConceptSpecializationExprClass, Empty) {}
54
55 ConceptSpecializationExpr *
Create(const ASTContext & C,ConceptReference * Loc,ImplicitConceptSpecializationDecl * SpecDecl,const ConstraintSatisfaction * Satisfaction)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
ConceptSpecializationExpr(const ASTContext & C,ConceptReference * Loc,ImplicitConceptSpecializationDecl * SpecDecl,const ConstraintSatisfaction * Satisfaction,bool Dependent,bool ContainsUnexpandedParameterPack)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)
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 *
Create(const ASTContext & C,ConceptReference * Loc,ImplicitConceptSpecializationDecl * SpecDecl,const ConstraintSatisfaction * Satisfaction,bool Dependent,bool ContainsUnexpandedParameterPack)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 *
getTypeConstraint() const94 concepts::ExprRequirement::ReturnTypeRequirement::getTypeConstraint() const {
95 assert(isTypeConstraint());
96 auto TPL = cast<TemplateParameterList *>(TypeConstraintInfo.getPointer());
97 return cast<TemplateTypeParmDecl>(TPL->getParam(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.
RequirementContainsError(concepts::Requirement * R)103 static bool RequirementContainsError(concepts::Requirement *R) {
104 if (auto *ExprReq = dyn_cast<concepts::ExprRequirement>(R))
105 return ExprReq->getExpr() && ExprReq->getExpr()->containsErrors();
106
107 if (auto *NestedReq = dyn_cast<concepts::NestedRequirement>(R))
108 return !NestedReq->hasInvalidConstraint() &&
109 NestedReq->getConstraintExpr() &&
110 NestedReq->getConstraintExpr()->containsErrors();
111 return false;
112 }
113
RequiresExpr(ASTContext & C,SourceLocation RequiresKWLoc,RequiresExprBodyDecl * Body,SourceLocation LParenLoc,ArrayRef<ParmVarDecl * > LocalParameters,SourceLocation RParenLoc,ArrayRef<concepts::Requirement * > Requirements,SourceLocation RBraceLoc)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(LocalParameters, getTrailingObjects<ParmVarDecl *>());
147 llvm::copy(Requirements, 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
RequiresExpr(ASTContext & C,EmptyShell Empty,unsigned NumLocalParameters,unsigned NumRequirements)160 RequiresExpr::RequiresExpr(ASTContext &C, EmptyShell Empty,
161 unsigned NumLocalParameters,
162 unsigned NumRequirements)
163 : Expr(RequiresExprClass, Empty), NumLocalParameters(NumLocalParameters),
164 NumRequirements(NumRequirements) { }
165
Create(ASTContext & C,SourceLocation RequiresKWLoc,RequiresExprBodyDecl * Body,SourceLocation LParenLoc,ArrayRef<ParmVarDecl * > LocalParameters,SourceLocation RParenLoc,ArrayRef<concepts::Requirement * > Requirements,SourceLocation RBraceLoc)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(totalSizeToAlloc<ParmVarDecl *, concepts::Requirement *>(
173 LocalParameters.size(), Requirements.size()),
174 alignof(RequiresExpr));
175 return new (Mem)
176 RequiresExpr(C, RequiresKWLoc, Body, LParenLoc, LocalParameters,
177 RParenLoc, Requirements, RBraceLoc);
178 }
179
180 RequiresExpr *
Create(ASTContext & C,EmptyShell Empty,unsigned NumLocalParameters,unsigned NumRequirements)181 RequiresExpr::Create(ASTContext &C, EmptyShell Empty,
182 unsigned NumLocalParameters, unsigned NumRequirements) {
183 void *Mem =
184 C.Allocate(totalSizeToAlloc<ParmVarDecl *, concepts::Requirement *>(
185 NumLocalParameters, NumRequirements),
186 alignof(RequiresExpr));
187 return new (Mem) RequiresExpr(C, Empty, NumLocalParameters, NumRequirements);
188 }
189