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