xref: /llvm-project/clang/lib/AST/ExprConcepts.cpp (revision 63d9ef5e37539b8920eb6c93524e4be2c33a510c)
1a0f50d73SSaar Raz //===- ExprCXX.cpp - (C++) Expression AST Node Implementation -------------===//
2a0f50d73SSaar Raz //
3a0f50d73SSaar Raz // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4a0f50d73SSaar Raz // See https://llvm.org/LICENSE.txt for license information.
5a0f50d73SSaar Raz // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a0f50d73SSaar Raz //
7a0f50d73SSaar Raz //===----------------------------------------------------------------------===//
8a0f50d73SSaar Raz //
9a0f50d73SSaar Raz // This file implements the subclesses of Expr class declared in ExprCXX.h
10a0f50d73SSaar Raz //
11a0f50d73SSaar Raz //===----------------------------------------------------------------------===//
12a0f50d73SSaar Raz 
13a0f50d73SSaar Raz #include "clang/AST/ExprConcepts.h"
14a0f50d73SSaar Raz #include "clang/AST/ASTConcept.h"
15ec3060c7SIlya Biryukov #include "clang/AST/ASTContext.h"
16876bb86eSHaojian Wu #include "clang/AST/ComputeDependence.h"
17a0f50d73SSaar Raz #include "clang/AST/Decl.h"
18a0f50d73SSaar Raz #include "clang/AST/DeclTemplate.h"
19ec3060c7SIlya Biryukov #include "clang/AST/DeclarationName.h"
2067d25914SHaojian Wu #include "clang/AST/DependenceFlags.h"
21a0f50d73SSaar Raz #include "clang/AST/Expr.h"
22a0f50d73SSaar Raz #include "clang/AST/NestedNameSpecifier.h"
23a0f50d73SSaar Raz #include "clang/AST/TemplateBase.h"
24a0f50d73SSaar Raz #include "clang/AST/Type.h"
25a0f50d73SSaar Raz #include "clang/Basic/SourceLocation.h"
26a0f50d73SSaar Raz #include <algorithm>
27a0f50d73SSaar Raz 
28a0f50d73SSaar Raz using namespace clang;
29a0f50d73SSaar Raz 
30876bb86eSHaojian Wu ConceptSpecializationExpr::ConceptSpecializationExpr(
31c2bf9bafSJens Massberg     const ASTContext &C, ConceptReference *Loc,
32975740bfSErich Keane     ImplicitConceptSpecializationDecl *SpecDecl,
33a0f50d73SSaar Raz     const ConstraintSatisfaction *Satisfaction)
34aef5d8fdSMatheus Izvekov     : Expr(ConceptSpecializationExprClass, C.BoolTy, VK_PRValue, OK_Ordinary),
35c2bf9bafSJens Massberg       ConceptRef(Loc), SpecDecl(SpecDecl),
36876bb86eSHaojian Wu       Satisfaction(Satisfaction
37876bb86eSHaojian Wu                        ? ASTConstraintSatisfaction::Create(C, *Satisfaction)
38876bb86eSHaojian Wu                        : nullptr) {
39876bb86eSHaojian Wu   setDependence(computeDependence(this, /*ValueDependent=*/!Satisfaction));
40a0f50d73SSaar Raz 
41a0f50d73SSaar Raz   // Currently guaranteed by the fact concepts can only be at namespace-scope.
42c2bf9bafSJens Massberg   assert(!Loc->getNestedNameSpecifierLoc() ||
43c2bf9bafSJens Massberg          (!Loc->getNestedNameSpecifierLoc()
44c2bf9bafSJens Massberg                .getNestedNameSpecifier()
45c2bf9bafSJens Massberg                ->isInstantiationDependent() &&
46c2bf9bafSJens Massberg           !Loc->getNestedNameSpecifierLoc()
47c2bf9bafSJens Massberg                .getNestedNameSpecifier()
48a0f50d73SSaar Raz                ->containsUnexpandedParameterPack()));
49a0f50d73SSaar Raz   assert((!isValueDependent() || isInstantiationDependent()) &&
50a0f50d73SSaar Raz          "should not be value-dependent");
51a0f50d73SSaar Raz }
52a0f50d73SSaar Raz 
53975740bfSErich Keane ConceptSpecializationExpr::ConceptSpecializationExpr(EmptyShell Empty)
54975740bfSErich Keane     : Expr(ConceptSpecializationExprClass, Empty) {}
55c83d9bedSSaar Raz 
56c2bf9bafSJens Massberg ConceptSpecializationExpr *
57c2bf9bafSJens Massberg ConceptSpecializationExpr::Create(const ASTContext &C, ConceptReference *Loc,
58975740bfSErich Keane                                   ImplicitConceptSpecializationDecl *SpecDecl,
59a0f50d73SSaar Raz                                   const ConstraintSatisfaction *Satisfaction) {
60c2bf9bafSJens Massberg   return new (C) ConceptSpecializationExpr(C, Loc, SpecDecl, Satisfaction);
61a0f50d73SSaar Raz }
62a0f50d73SSaar Raz 
63c83d9bedSSaar Raz ConceptSpecializationExpr::ConceptSpecializationExpr(
64c2bf9bafSJens Massberg     const ASTContext &C, ConceptReference *Loc,
65975740bfSErich Keane     ImplicitConceptSpecializationDecl *SpecDecl,
66c83d9bedSSaar Raz     const ConstraintSatisfaction *Satisfaction, bool Dependent,
67c83d9bedSSaar Raz     bool ContainsUnexpandedParameterPack)
68aef5d8fdSMatheus Izvekov     : Expr(ConceptSpecializationExprClass, C.BoolTy, VK_PRValue, OK_Ordinary),
69c2bf9bafSJens Massberg       ConceptRef(Loc), SpecDecl(SpecDecl),
70876bb86eSHaojian Wu       Satisfaction(Satisfaction
71876bb86eSHaojian Wu                        ? ASTConstraintSatisfaction::Create(C, *Satisfaction)
72876bb86eSHaojian Wu                        : nullptr) {
73876bb86eSHaojian Wu   ExprDependence D = ExprDependence::None;
74876bb86eSHaojian Wu   if (!Satisfaction)
75876bb86eSHaojian Wu     D |= ExprDependence::Value;
76876bb86eSHaojian Wu   if (Dependent)
77876bb86eSHaojian Wu     D |= ExprDependence::Instantiation;
78876bb86eSHaojian Wu   if (ContainsUnexpandedParameterPack)
79876bb86eSHaojian Wu     D |= ExprDependence::UnexpandedPack;
80876bb86eSHaojian Wu   setDependence(D);
81c83d9bedSSaar Raz }
82c83d9bedSSaar Raz 
83c2bf9bafSJens Massberg ConceptSpecializationExpr *
84c2bf9bafSJens Massberg ConceptSpecializationExpr::Create(const ASTContext &C, ConceptReference *Loc,
85975740bfSErich Keane                                   ImplicitConceptSpecializationDecl *SpecDecl,
86c2bf9bafSJens Massberg                                   const ConstraintSatisfaction *Satisfaction,
87c2bf9bafSJens Massberg                                   bool Dependent,
88c83d9bedSSaar Raz                                   bool ContainsUnexpandedParameterPack) {
89c2bf9bafSJens Massberg   return new (C)
90c2bf9bafSJens Massberg       ConceptSpecializationExpr(C, Loc, SpecDecl, Satisfaction, Dependent,
911f48a1fcSWalter Gray                                 ContainsUnexpandedParameterPack);
92a0f50d73SSaar Raz }
93a0f50d73SSaar Raz 
94a0f50d73SSaar Raz const TypeConstraint *
95a0f50d73SSaar Raz concepts::ExprRequirement::ReturnTypeRequirement::getTypeConstraint() const {
96a0f50d73SSaar Raz   assert(isTypeConstraint());
97*63d9ef5eSKazu Hirata   auto TPL = cast<TemplateParameterList *>(TypeConstraintInfo.getPointer());
98a0f50d73SSaar Raz   return cast<TemplateTypeParmDecl>(TPL->getParam(0))
99a0f50d73SSaar Raz       ->getTypeConstraint();
100a0f50d73SSaar Raz }
101a0f50d73SSaar Raz 
10298ea4712SErich Keane // Search through the requirements, and see if any have a RecoveryExpr in it,
10398ea4712SErich Keane // which means this RequiresExpr ALSO needs to be invalid.
10498ea4712SErich Keane static bool RequirementContainsError(concepts::Requirement *R) {
10598ea4712SErich Keane   if (auto *ExprReq = dyn_cast<concepts::ExprRequirement>(R))
10698ea4712SErich Keane     return ExprReq->getExpr() && ExprReq->getExpr()->containsErrors();
10798ea4712SErich Keane 
10898ea4712SErich Keane   if (auto *NestedReq = dyn_cast<concepts::NestedRequirement>(R))
10998ea4712SErich Keane     return !NestedReq->hasInvalidConstraint() &&
11098ea4712SErich Keane            NestedReq->getConstraintExpr() &&
11198ea4712SErich Keane            NestedReq->getConstraintExpr()->containsErrors();
11298ea4712SErich Keane   return false;
11398ea4712SErich Keane }
11498ea4712SErich Keane 
115a0f50d73SSaar Raz RequiresExpr::RequiresExpr(ASTContext &C, SourceLocation RequiresKWLoc,
1164b163e34SRichard Smith                            RequiresExprBodyDecl *Body, SourceLocation LParenLoc,
117a0f50d73SSaar Raz                            ArrayRef<ParmVarDecl *> LocalParameters,
1184b163e34SRichard Smith                            SourceLocation RParenLoc,
119a0f50d73SSaar Raz                            ArrayRef<concepts::Requirement *> Requirements,
120a0f50d73SSaar Raz                            SourceLocation RBraceLoc)
121aef5d8fdSMatheus Izvekov     : Expr(RequiresExprClass, C.BoolTy, VK_PRValue, OK_Ordinary),
122a0f50d73SSaar Raz       NumLocalParameters(LocalParameters.size()),
1234b163e34SRichard Smith       NumRequirements(Requirements.size()), Body(Body), LParenLoc(LParenLoc),
1244b163e34SRichard Smith       RParenLoc(RParenLoc), RBraceLoc(RBraceLoc) {
125a0f50d73SSaar Raz   RequiresExprBits.IsSatisfied = false;
126a0f50d73SSaar Raz   RequiresExprBits.RequiresKWLoc = RequiresKWLoc;
127a0f50d73SSaar Raz   bool Dependent = false;
128a0f50d73SSaar Raz   bool ContainsUnexpandedParameterPack = false;
129a0f50d73SSaar Raz   for (ParmVarDecl *P : LocalParameters) {
130a0f50d73SSaar Raz     Dependent |= P->getType()->isInstantiationDependentType();
131a0f50d73SSaar Raz     ContainsUnexpandedParameterPack |=
132a0f50d73SSaar Raz         P->getType()->containsUnexpandedParameterPack();
133a0f50d73SSaar Raz   }
134a0f50d73SSaar Raz   RequiresExprBits.IsSatisfied = true;
135a0f50d73SSaar Raz   for (concepts::Requirement *R : Requirements) {
136a0f50d73SSaar Raz     Dependent |= R->isDependent();
137a0f50d73SSaar Raz     ContainsUnexpandedParameterPack |= R->containsUnexpandedParameterPack();
138a0f50d73SSaar Raz     if (!Dependent) {
139a0f50d73SSaar Raz       RequiresExprBits.IsSatisfied = R->isSatisfied();
140a0f50d73SSaar Raz       if (!RequiresExprBits.IsSatisfied)
141a0f50d73SSaar Raz         break;
142a0f50d73SSaar Raz     }
14398ea4712SErich Keane 
14498ea4712SErich Keane     if (RequirementContainsError(R))
14598ea4712SErich Keane       setDependence(getDependence() | ExprDependence::Error);
146a0f50d73SSaar Raz   }
147a0f50d73SSaar Raz   std::copy(LocalParameters.begin(), LocalParameters.end(),
148a0f50d73SSaar Raz             getTrailingObjects<ParmVarDecl *>());
149a0f50d73SSaar Raz   std::copy(Requirements.begin(), Requirements.end(),
150a0f50d73SSaar Raz             getTrailingObjects<concepts::Requirement *>());
151a0f50d73SSaar Raz   RequiresExprBits.IsSatisfied |= Dependent;
152876bb86eSHaojian Wu   // FIXME: move the computing dependency logic to ComputeDependence.h
153ec3060c7SIlya Biryukov   if (ContainsUnexpandedParameterPack)
154b4f02d89SSam McCall     setDependence(getDependence() | ExprDependence::UnexpandedPack);
155ec3060c7SIlya Biryukov   // FIXME: this is incorrect for cases where we have a non-dependent
156ec3060c7SIlya Biryukov   // requirement, but its parameters are instantiation-dependent. RequiresExpr
157ec3060c7SIlya Biryukov   // should be instantiation-dependent if it has instantiation-dependent
158ec3060c7SIlya Biryukov   // parameters.
159ec3060c7SIlya Biryukov   if (Dependent)
160b4f02d89SSam McCall     setDependence(getDependence() | ExprDependence::ValueInstantiation);
161a0f50d73SSaar Raz }
162a0f50d73SSaar Raz 
163a0f50d73SSaar Raz RequiresExpr::RequiresExpr(ASTContext &C, EmptyShell Empty,
164a0f50d73SSaar Raz                            unsigned NumLocalParameters,
165a0f50d73SSaar Raz                            unsigned NumRequirements)
166a0f50d73SSaar Raz   : Expr(RequiresExprClass, Empty), NumLocalParameters(NumLocalParameters),
167a0f50d73SSaar Raz     NumRequirements(NumRequirements) { }
168a0f50d73SSaar Raz 
1694b163e34SRichard Smith RequiresExpr *RequiresExpr::Create(
1704b163e34SRichard Smith     ASTContext &C, SourceLocation RequiresKWLoc, RequiresExprBodyDecl *Body,
1714b163e34SRichard Smith     SourceLocation LParenLoc, ArrayRef<ParmVarDecl *> LocalParameters,
1724b163e34SRichard Smith     SourceLocation RParenLoc, ArrayRef<concepts::Requirement *> Requirements,
173a0f50d73SSaar Raz     SourceLocation RBraceLoc) {
174a0f50d73SSaar Raz   void *Mem =
175a0f50d73SSaar Raz       C.Allocate(totalSizeToAlloc<ParmVarDecl *, concepts::Requirement *>(
176a0f50d73SSaar Raz                      LocalParameters.size(), Requirements.size()),
177a0f50d73SSaar Raz                  alignof(RequiresExpr));
1784b163e34SRichard Smith   return new (Mem)
1794b163e34SRichard Smith       RequiresExpr(C, RequiresKWLoc, Body, LParenLoc, LocalParameters,
1804b163e34SRichard Smith                    RParenLoc, Requirements, RBraceLoc);
181a0f50d73SSaar Raz }
182a0f50d73SSaar Raz 
183a0f50d73SSaar Raz RequiresExpr *
184a0f50d73SSaar Raz RequiresExpr::Create(ASTContext &C, EmptyShell Empty,
185a0f50d73SSaar Raz                      unsigned NumLocalParameters, unsigned NumRequirements) {
186a0f50d73SSaar Raz   void *Mem =
187a0f50d73SSaar Raz       C.Allocate(totalSizeToAlloc<ParmVarDecl *, concepts::Requirement *>(
188a0f50d73SSaar Raz                      NumLocalParameters, NumRequirements),
189a0f50d73SSaar Raz                  alignof(RequiresExpr));
190a0f50d73SSaar Raz   return new (Mem) RequiresExpr(C, Empty, NumLocalParameters, NumRequirements);
191a0f50d73SSaar Raz }
192