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