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
ConceptSpecializationExpr(const ASTContext & C,NestedNameSpecifierLoc NNS,SourceLocation TemplateKWLoc,DeclarationNameInfo ConceptNameInfo,NamedDecl * FoundDecl,ConceptDecl * NamedConcept,const ASTTemplateArgumentListInfo * ArgsAsWritten,ArrayRef<TemplateArgument> ConvertedArgs,const ConstraintSatisfaction * Satisfaction)33 ConceptSpecializationExpr::ConceptSpecializationExpr(
34 const ASTContext &C, NestedNameSpecifierLoc NNS,
35 SourceLocation TemplateKWLoc, DeclarationNameInfo ConceptNameInfo,
36 NamedDecl *FoundDecl, ConceptDecl *NamedConcept,
37 const ASTTemplateArgumentListInfo *ArgsAsWritten,
38 ArrayRef<TemplateArgument> ConvertedArgs,
39 const ConstraintSatisfaction *Satisfaction)
40 : Expr(ConceptSpecializationExprClass, C.BoolTy, VK_PRValue, OK_Ordinary),
41 ConceptReference(NNS, TemplateKWLoc, ConceptNameInfo, FoundDecl,
42 NamedConcept, ArgsAsWritten),
43 NumTemplateArgs(ConvertedArgs.size()),
44 Satisfaction(Satisfaction
45 ? ASTConstraintSatisfaction::Create(C, *Satisfaction)
46 : nullptr) {
47 setTemplateArguments(ConvertedArgs);
48 setDependence(computeDependence(this, /*ValueDependent=*/!Satisfaction));
49
50 // Currently guaranteed by the fact concepts can only be at namespace-scope.
51 assert(!NestedNameSpec ||
52 (!NestedNameSpec.getNestedNameSpecifier()->isInstantiationDependent() &&
53 !NestedNameSpec.getNestedNameSpecifier()
54 ->containsUnexpandedParameterPack()));
55 assert((!isValueDependent() || isInstantiationDependent()) &&
56 "should not be value-dependent");
57 }
58
ConceptSpecializationExpr(EmptyShell Empty,unsigned NumTemplateArgs)59 ConceptSpecializationExpr::ConceptSpecializationExpr(EmptyShell Empty,
60 unsigned NumTemplateArgs)
61 : Expr(ConceptSpecializationExprClass, Empty), ConceptReference(),
62 NumTemplateArgs(NumTemplateArgs) { }
63
setTemplateArguments(ArrayRef<TemplateArgument> Converted)64 void ConceptSpecializationExpr::setTemplateArguments(
65 ArrayRef<TemplateArgument> Converted) {
66 assert(Converted.size() == NumTemplateArgs);
67 std::uninitialized_copy(Converted.begin(), Converted.end(),
68 getTrailingObjects<TemplateArgument>());
69 }
70
71 ConceptSpecializationExpr *
Create(const ASTContext & C,NestedNameSpecifierLoc NNS,SourceLocation TemplateKWLoc,DeclarationNameInfo ConceptNameInfo,NamedDecl * FoundDecl,ConceptDecl * NamedConcept,const ASTTemplateArgumentListInfo * ArgsAsWritten,ArrayRef<TemplateArgument> ConvertedArgs,const ConstraintSatisfaction * Satisfaction)72 ConceptSpecializationExpr::Create(const ASTContext &C,
73 NestedNameSpecifierLoc NNS,
74 SourceLocation TemplateKWLoc,
75 DeclarationNameInfo ConceptNameInfo,
76 NamedDecl *FoundDecl,
77 ConceptDecl *NamedConcept,
78 const ASTTemplateArgumentListInfo *ArgsAsWritten,
79 ArrayRef<TemplateArgument> ConvertedArgs,
80 const ConstraintSatisfaction *Satisfaction) {
81 void *Buffer = C.Allocate(totalSizeToAlloc<TemplateArgument>(
82 ConvertedArgs.size()));
83 return new (Buffer) ConceptSpecializationExpr(C, NNS, TemplateKWLoc,
84 ConceptNameInfo, FoundDecl,
85 NamedConcept, ArgsAsWritten,
86 ConvertedArgs, Satisfaction);
87 }
88
ConceptSpecializationExpr(const ASTContext & C,ConceptDecl * NamedConcept,ArrayRef<TemplateArgument> ConvertedArgs,const ConstraintSatisfaction * Satisfaction,bool Dependent,bool ContainsUnexpandedParameterPack)89 ConceptSpecializationExpr::ConceptSpecializationExpr(
90 const ASTContext &C, ConceptDecl *NamedConcept,
91 ArrayRef<TemplateArgument> ConvertedArgs,
92 const ConstraintSatisfaction *Satisfaction, bool Dependent,
93 bool ContainsUnexpandedParameterPack)
94 : Expr(ConceptSpecializationExprClass, C.BoolTy, VK_PRValue, OK_Ordinary),
95 ConceptReference(NestedNameSpecifierLoc(), SourceLocation(),
96 DeclarationNameInfo(), NamedConcept, NamedConcept,
97 nullptr),
98 NumTemplateArgs(ConvertedArgs.size()),
99 Satisfaction(Satisfaction
100 ? ASTConstraintSatisfaction::Create(C, *Satisfaction)
101 : nullptr) {
102 setTemplateArguments(ConvertedArgs);
103 ExprDependence D = ExprDependence::None;
104 if (!Satisfaction)
105 D |= ExprDependence::Value;
106 if (Dependent)
107 D |= ExprDependence::Instantiation;
108 if (ContainsUnexpandedParameterPack)
109 D |= ExprDependence::UnexpandedPack;
110 setDependence(D);
111 }
112
113 ConceptSpecializationExpr *
Create(const ASTContext & C,ConceptDecl * NamedConcept,ArrayRef<TemplateArgument> ConvertedArgs,const ConstraintSatisfaction * Satisfaction,bool Dependent,bool ContainsUnexpandedParameterPack)114 ConceptSpecializationExpr::Create(const ASTContext &C,
115 ConceptDecl *NamedConcept,
116 ArrayRef<TemplateArgument> ConvertedArgs,
117 const ConstraintSatisfaction *Satisfaction,
118 bool Dependent,
119 bool ContainsUnexpandedParameterPack) {
120 void *Buffer = C.Allocate(totalSizeToAlloc<TemplateArgument>(
121 ConvertedArgs.size()));
122 return new (Buffer) ConceptSpecializationExpr(
123 C, NamedConcept, ConvertedArgs, Satisfaction, Dependent,
124 ContainsUnexpandedParameterPack);
125 }
126
127 ConceptSpecializationExpr *
Create(ASTContext & C,EmptyShell Empty,unsigned NumTemplateArgs)128 ConceptSpecializationExpr::Create(ASTContext &C, EmptyShell Empty,
129 unsigned NumTemplateArgs) {
130 void *Buffer = C.Allocate(totalSizeToAlloc<TemplateArgument>(
131 NumTemplateArgs));
132 return new (Buffer) ConceptSpecializationExpr(Empty, NumTemplateArgs);
133 }
134
135 const TypeConstraint *
getTypeConstraint() const136 concepts::ExprRequirement::ReturnTypeRequirement::getTypeConstraint() const {
137 assert(isTypeConstraint());
138 auto TPL =
139 TypeConstraintInfo.getPointer().get<TemplateParameterList *>();
140 return cast<TemplateTypeParmDecl>(TPL->getParam(0))
141 ->getTypeConstraint();
142 }
143
RequiresExpr(ASTContext & C,SourceLocation RequiresKWLoc,RequiresExprBodyDecl * Body,ArrayRef<ParmVarDecl * > LocalParameters,ArrayRef<concepts::Requirement * > Requirements,SourceLocation RBraceLoc)144 RequiresExpr::RequiresExpr(ASTContext &C, SourceLocation RequiresKWLoc,
145 RequiresExprBodyDecl *Body,
146 ArrayRef<ParmVarDecl *> LocalParameters,
147 ArrayRef<concepts::Requirement *> Requirements,
148 SourceLocation RBraceLoc)
149 : Expr(RequiresExprClass, C.BoolTy, VK_PRValue, OK_Ordinary),
150 NumLocalParameters(LocalParameters.size()),
151 NumRequirements(Requirements.size()), Body(Body), RBraceLoc(RBraceLoc) {
152 RequiresExprBits.IsSatisfied = false;
153 RequiresExprBits.RequiresKWLoc = RequiresKWLoc;
154 bool Dependent = false;
155 bool ContainsUnexpandedParameterPack = false;
156 for (ParmVarDecl *P : LocalParameters) {
157 Dependent |= P->getType()->isInstantiationDependentType();
158 ContainsUnexpandedParameterPack |=
159 P->getType()->containsUnexpandedParameterPack();
160 }
161 RequiresExprBits.IsSatisfied = true;
162 for (concepts::Requirement *R : Requirements) {
163 Dependent |= R->isDependent();
164 ContainsUnexpandedParameterPack |= R->containsUnexpandedParameterPack();
165 if (!Dependent) {
166 RequiresExprBits.IsSatisfied = R->isSatisfied();
167 if (!RequiresExprBits.IsSatisfied)
168 break;
169 }
170 }
171 std::copy(LocalParameters.begin(), LocalParameters.end(),
172 getTrailingObjects<ParmVarDecl *>());
173 std::copy(Requirements.begin(), Requirements.end(),
174 getTrailingObjects<concepts::Requirement *>());
175 RequiresExprBits.IsSatisfied |= Dependent;
176 // FIXME: move the computing dependency logic to ComputeDependence.h
177 if (ContainsUnexpandedParameterPack)
178 setDependence(getDependence() | ExprDependence::UnexpandedPack);
179 // FIXME: this is incorrect for cases where we have a non-dependent
180 // requirement, but its parameters are instantiation-dependent. RequiresExpr
181 // should be instantiation-dependent if it has instantiation-dependent
182 // parameters.
183 if (Dependent)
184 setDependence(getDependence() | ExprDependence::ValueInstantiation);
185 }
186
RequiresExpr(ASTContext & C,EmptyShell Empty,unsigned NumLocalParameters,unsigned NumRequirements)187 RequiresExpr::RequiresExpr(ASTContext &C, EmptyShell Empty,
188 unsigned NumLocalParameters,
189 unsigned NumRequirements)
190 : Expr(RequiresExprClass, Empty), NumLocalParameters(NumLocalParameters),
191 NumRequirements(NumRequirements) { }
192
193 RequiresExpr *
Create(ASTContext & C,SourceLocation RequiresKWLoc,RequiresExprBodyDecl * Body,ArrayRef<ParmVarDecl * > LocalParameters,ArrayRef<concepts::Requirement * > Requirements,SourceLocation RBraceLoc)194 RequiresExpr::Create(ASTContext &C, SourceLocation RequiresKWLoc,
195 RequiresExprBodyDecl *Body,
196 ArrayRef<ParmVarDecl *> LocalParameters,
197 ArrayRef<concepts::Requirement *> Requirements,
198 SourceLocation RBraceLoc) {
199 void *Mem =
200 C.Allocate(totalSizeToAlloc<ParmVarDecl *, concepts::Requirement *>(
201 LocalParameters.size(), Requirements.size()),
202 alignof(RequiresExpr));
203 return new (Mem) RequiresExpr(C, RequiresKWLoc, Body, LocalParameters,
204 Requirements, RBraceLoc);
205 }
206
207 RequiresExpr *
Create(ASTContext & C,EmptyShell Empty,unsigned NumLocalParameters,unsigned NumRequirements)208 RequiresExpr::Create(ASTContext &C, EmptyShell Empty,
209 unsigned NumLocalParameters, unsigned NumRequirements) {
210 void *Mem =
211 C.Allocate(totalSizeToAlloc<ParmVarDecl *, concepts::Requirement *>(
212 NumLocalParameters, NumRequirements),
213 alignof(RequiresExpr));
214 return new (Mem) RequiresExpr(C, Empty, NumLocalParameters, NumRequirements);
215 }
216