xref: /freebsd/contrib/llvm-project/clang/lib/AST/ExprConcepts.cpp (revision 9c77fb6aaa366cbabc80ee1b834bcfe4df135491)
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 
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 
52 ConceptSpecializationExpr::ConceptSpecializationExpr(EmptyShell Empty)
53     : Expr(ConceptSpecializationExprClass, Empty) {}
54 
55 ConceptSpecializationExpr *
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 
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 *
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 *
94 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.
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 
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 
160 RequiresExpr::RequiresExpr(ASTContext &C, EmptyShell Empty,
161                            unsigned NumLocalParameters,
162                            unsigned NumRequirements)
163   : Expr(RequiresExprClass, Empty), NumLocalParameters(NumLocalParameters),
164     NumRequirements(NumRequirements) { }
165 
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 *
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