xref: /freebsd/contrib/llvm-project/clang/lib/AST/ExprConcepts.cpp (revision c57c26179033f64c2011a2d2a904ee3fa62e826a)
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, ConceptReference *Loc,
35     ImplicitConceptSpecializationDecl *SpecDecl,
36     const ConstraintSatisfaction *Satisfaction)
37     : Expr(ConceptSpecializationExprClass, C.BoolTy, VK_PRValue, OK_Ordinary),
38       ConceptRef(Loc), SpecDecl(SpecDecl),
39       Satisfaction(Satisfaction
40                        ? ASTConstraintSatisfaction::Create(C, *Satisfaction)
41                        : nullptr) {
42   setDependence(computeDependence(this, /*ValueDependent=*/!Satisfaction));
43 
44   // Currently guaranteed by the fact concepts can only be at namespace-scope.
45   assert(!Loc->getNestedNameSpecifierLoc() ||
46          (!Loc->getNestedNameSpecifierLoc()
47                .getNestedNameSpecifier()
48                ->isInstantiationDependent() &&
49           !Loc->getNestedNameSpecifierLoc()
50                .getNestedNameSpecifier()
51                ->containsUnexpandedParameterPack()));
52   assert((!isValueDependent() || isInstantiationDependent()) &&
53          "should not be value-dependent");
54 }
55 
56 ConceptSpecializationExpr::ConceptSpecializationExpr(EmptyShell Empty)
57     : Expr(ConceptSpecializationExprClass, Empty) {}
58 
59 ConceptSpecializationExpr *
60 ConceptSpecializationExpr::Create(const ASTContext &C, ConceptReference *Loc,
61                                   ImplicitConceptSpecializationDecl *SpecDecl,
62                                   const ConstraintSatisfaction *Satisfaction) {
63   return new (C) ConceptSpecializationExpr(C, Loc, SpecDecl, Satisfaction);
64 }
65 
66 ConceptSpecializationExpr::ConceptSpecializationExpr(
67     const ASTContext &C, ConceptReference *Loc,
68     ImplicitConceptSpecializationDecl *SpecDecl,
69     const ConstraintSatisfaction *Satisfaction, bool Dependent,
70     bool ContainsUnexpandedParameterPack)
71     : Expr(ConceptSpecializationExprClass, C.BoolTy, VK_PRValue, OK_Ordinary),
72       ConceptRef(Loc), SpecDecl(SpecDecl),
73       Satisfaction(Satisfaction
74                        ? ASTConstraintSatisfaction::Create(C, *Satisfaction)
75                        : nullptr) {
76   ExprDependence D = ExprDependence::None;
77   if (!Satisfaction)
78     D |= ExprDependence::Value;
79   if (Dependent)
80     D |= ExprDependence::Instantiation;
81   if (ContainsUnexpandedParameterPack)
82     D |= ExprDependence::UnexpandedPack;
83   setDependence(D);
84 }
85 
86 ConceptSpecializationExpr *
87 ConceptSpecializationExpr::Create(const ASTContext &C, ConceptReference *Loc,
88                                   ImplicitConceptSpecializationDecl *SpecDecl,
89                                   const ConstraintSatisfaction *Satisfaction,
90                                   bool Dependent,
91                                   bool ContainsUnexpandedParameterPack) {
92   return new (C)
93       ConceptSpecializationExpr(C, Loc, SpecDecl, Satisfaction, Dependent,
94                                 ContainsUnexpandedParameterPack);
95 }
96 
97 const TypeConstraint *
98 concepts::ExprRequirement::ReturnTypeRequirement::getTypeConstraint() const {
99   assert(isTypeConstraint());
100   auto TPL =
101       TypeConstraintInfo.getPointer().get<TemplateParameterList *>();
102   return cast<TemplateTypeParmDecl>(TPL->getParam(0))
103       ->getTypeConstraint();
104 }
105 
106 // Search through the requirements, and see if any have a RecoveryExpr in it,
107 // which means this RequiresExpr ALSO needs to be invalid.
108 static bool RequirementContainsError(concepts::Requirement *R) {
109   if (auto *ExprReq = dyn_cast<concepts::ExprRequirement>(R))
110     return ExprReq->getExpr() && ExprReq->getExpr()->containsErrors();
111 
112   if (auto *NestedReq = dyn_cast<concepts::NestedRequirement>(R))
113     return !NestedReq->hasInvalidConstraint() &&
114            NestedReq->getConstraintExpr() &&
115            NestedReq->getConstraintExpr()->containsErrors();
116   return false;
117 }
118 
119 RequiresExpr::RequiresExpr(ASTContext &C, SourceLocation RequiresKWLoc,
120                            RequiresExprBodyDecl *Body, SourceLocation LParenLoc,
121                            ArrayRef<ParmVarDecl *> LocalParameters,
122                            SourceLocation RParenLoc,
123                            ArrayRef<concepts::Requirement *> Requirements,
124                            SourceLocation RBraceLoc)
125     : Expr(RequiresExprClass, C.BoolTy, VK_PRValue, OK_Ordinary),
126       NumLocalParameters(LocalParameters.size()),
127       NumRequirements(Requirements.size()), Body(Body), LParenLoc(LParenLoc),
128       RParenLoc(RParenLoc), RBraceLoc(RBraceLoc) {
129   RequiresExprBits.IsSatisfied = false;
130   RequiresExprBits.RequiresKWLoc = RequiresKWLoc;
131   bool Dependent = false;
132   bool ContainsUnexpandedParameterPack = false;
133   for (ParmVarDecl *P : LocalParameters) {
134     Dependent |= P->getType()->isInstantiationDependentType();
135     ContainsUnexpandedParameterPack |=
136         P->getType()->containsUnexpandedParameterPack();
137   }
138   RequiresExprBits.IsSatisfied = true;
139   for (concepts::Requirement *R : Requirements) {
140     Dependent |= R->isDependent();
141     ContainsUnexpandedParameterPack |= R->containsUnexpandedParameterPack();
142     if (!Dependent) {
143       RequiresExprBits.IsSatisfied = R->isSatisfied();
144       if (!RequiresExprBits.IsSatisfied)
145         break;
146     }
147 
148     if (RequirementContainsError(R))
149       setDependence(getDependence() | ExprDependence::Error);
150   }
151   std::copy(LocalParameters.begin(), LocalParameters.end(),
152             getTrailingObjects<ParmVarDecl *>());
153   std::copy(Requirements.begin(), Requirements.end(),
154             getTrailingObjects<concepts::Requirement *>());
155   RequiresExprBits.IsSatisfied |= Dependent;
156   // FIXME: move the computing dependency logic to ComputeDependence.h
157   if (ContainsUnexpandedParameterPack)
158     setDependence(getDependence() | ExprDependence::UnexpandedPack);
159   // FIXME: this is incorrect for cases where we have a non-dependent
160   // requirement, but its parameters are instantiation-dependent. RequiresExpr
161   // should be instantiation-dependent if it has instantiation-dependent
162   // parameters.
163   if (Dependent)
164     setDependence(getDependence() | ExprDependence::ValueInstantiation);
165 }
166 
167 RequiresExpr::RequiresExpr(ASTContext &C, EmptyShell Empty,
168                            unsigned NumLocalParameters,
169                            unsigned NumRequirements)
170   : Expr(RequiresExprClass, Empty), NumLocalParameters(NumLocalParameters),
171     NumRequirements(NumRequirements) { }
172 
173 RequiresExpr *RequiresExpr::Create(
174     ASTContext &C, SourceLocation RequiresKWLoc, RequiresExprBodyDecl *Body,
175     SourceLocation LParenLoc, ArrayRef<ParmVarDecl *> LocalParameters,
176     SourceLocation RParenLoc, ArrayRef<concepts::Requirement *> Requirements,
177     SourceLocation RBraceLoc) {
178   void *Mem =
179       C.Allocate(totalSizeToAlloc<ParmVarDecl *, concepts::Requirement *>(
180                      LocalParameters.size(), Requirements.size()),
181                  alignof(RequiresExpr));
182   return new (Mem)
183       RequiresExpr(C, RequiresKWLoc, Body, LParenLoc, LocalParameters,
184                    RParenLoc, Requirements, RBraceLoc);
185 }
186 
187 RequiresExpr *
188 RequiresExpr::Create(ASTContext &C, EmptyShell Empty,
189                      unsigned NumLocalParameters, unsigned NumRequirements) {
190   void *Mem =
191       C.Allocate(totalSizeToAlloc<ParmVarDecl *, concepts::Requirement *>(
192                      NumLocalParameters, NumRequirements),
193                  alignof(RequiresExpr));
194   return new (Mem) RequiresExpr(C, Empty, NumLocalParameters, NumRequirements);
195 }
196