xref: /llvm-project/clang/lib/AST/ExprConcepts.cpp (revision 63d9ef5e37539b8920eb6c93524e4be2c33a510c)
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)
38                        : nullptr) {
39   setDependence(computeDependence(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)
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 *>(TypeConstraintInfo.getPointer());
98   return cast<TemplateTypeParmDecl>(TPL->getParam(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>(R))
106     return ExprReq->getExpr() && ExprReq->getExpr()->containsErrors();
107 
108   if (auto *NestedReq = dyn_cast<concepts::NestedRequirement>(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(totalSizeToAlloc<ParmVarDecl *, concepts::Requirement *>(
176                      LocalParameters.size(), Requirements.size()),
177                  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(totalSizeToAlloc<ParmVarDecl *, concepts::Requirement *>(
188                      NumLocalParameters, NumRequirements),
189                  alignof(RequiresExpr));
190   return new (Mem) RequiresExpr(C, Empty, NumLocalParameters, NumRequirements);
191 }
192