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