| 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: *Satisfaction) |
| 37 | : nullptr) { |
| 38 | setDependence(computeDependence(E: 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: *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 *>(Val: TypeConstraintInfo.getPointer()); |
| 97 | return cast<TemplateTypeParmDecl>(Val: TPL->getParam(Idx: 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>(Val: R)) |
| 105 | return ExprReq->getExpr() && ExprReq->getExpr()->containsErrors(); |
| 106 | |
| 107 | if (auto *NestedReq = dyn_cast<concepts::NestedRequirement>(Val: 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(Range&: LocalParameters, Out: getTrailingObjects<ParmVarDecl *>()); |
| 147 | llvm::copy(Range&: Requirements, Out: 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(Size: totalSizeToAlloc<ParmVarDecl *, concepts::Requirement *>( |
| 173 | Counts: LocalParameters.size(), Counts: Requirements.size()), |
| 174 | Align: 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(Size: totalSizeToAlloc<ParmVarDecl *, concepts::Requirement *>( |
| 185 | Counts: NumLocalParameters, Counts: NumRequirements), |
| 186 | Align: alignof(RequiresExpr)); |
| 187 | return new (Mem) RequiresExpr(C, Empty, NumLocalParameters, NumRequirements); |
| 188 | } |
| 189 | |