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 
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_RValue, 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 
59 ConceptSpecializationExpr::ConceptSpecializationExpr(EmptyShell Empty,
60     unsigned NumTemplateArgs)
61     : Expr(ConceptSpecializationExprClass, Empty), ConceptReference(),
62       NumTemplateArgs(NumTemplateArgs) { }
63 
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 *
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 
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_RValue, 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 *
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 *
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 *
136 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 
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_RValue, 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 
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 *
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 *
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