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