199 lines · cpp
1//===--- ASTConcept.cpp - Concepts Related AST Data Structures --*- C++ -*-===//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-exception6//7//===----------------------------------------------------------------------===//8///9/// \file10/// \brief This file defines AST data structures related to concepts.11///12//===----------------------------------------------------------------------===//13 14#include "clang/AST/ASTConcept.h"15#include "clang/AST/ASTContext.h"16#include "clang/AST/ExprConcepts.h"17#include "clang/AST/NestedNameSpecifier.h"18#include "clang/AST/PrettyPrinter.h"19#include "llvm/ADT/StringExtras.h"20 21using namespace clang;22 23static void24CreateUnsatisfiedConstraintRecord(const ASTContext &C,25 const UnsatisfiedConstraintRecord &Detail,26 UnsatisfiedConstraintRecord *TrailingObject) {27 if (Detail.isNull())28 new (TrailingObject) UnsatisfiedConstraintRecord(nullptr);29 else if (const auto *E = llvm::dyn_cast<const Expr *>(Detail))30 new (TrailingObject) UnsatisfiedConstraintRecord(E);31 else if (const auto *Concept =32 llvm::dyn_cast<const ConceptReference *>(Detail))33 new (TrailingObject) UnsatisfiedConstraintRecord(Concept);34 else {35 auto &SubstitutionDiagnostic =36 *cast<const clang::ConstraintSubstitutionDiagnostic *>(Detail);37 StringRef Message = C.backupStr(SubstitutionDiagnostic.second);38 auto *NewSubstDiag = new (C) clang::ConstraintSubstitutionDiagnostic(39 SubstitutionDiagnostic.first, Message);40 new (TrailingObject) UnsatisfiedConstraintRecord(NewSubstDiag);41 }42}43 44ASTConstraintSatisfaction::ASTConstraintSatisfaction(45 const ASTContext &C, const ConstraintSatisfaction &Satisfaction)46 : NumRecords{Satisfaction.Details.size()},47 IsSatisfied{Satisfaction.IsSatisfied}, ContainsErrors{48 Satisfaction.ContainsErrors} {49 for (unsigned I = 0; I < NumRecords; ++I)50 CreateUnsatisfiedConstraintRecord(C, Satisfaction.Details[I],51 getTrailingObjects() + I);52}53 54ASTConstraintSatisfaction::ASTConstraintSatisfaction(55 const ASTContext &C, const ASTConstraintSatisfaction &Satisfaction)56 : NumRecords{Satisfaction.NumRecords},57 IsSatisfied{Satisfaction.IsSatisfied},58 ContainsErrors{Satisfaction.ContainsErrors} {59 for (unsigned I = 0; I < NumRecords; ++I)60 CreateUnsatisfiedConstraintRecord(C, *(Satisfaction.begin() + I),61 getTrailingObjects() + I);62}63 64ASTConstraintSatisfaction *65ASTConstraintSatisfaction::Create(const ASTContext &C,66 const ConstraintSatisfaction &Satisfaction) {67 std::size_t size =68 totalSizeToAlloc<UnsatisfiedConstraintRecord>(69 Satisfaction.Details.size());70 void *Mem = C.Allocate(size, alignof(ASTConstraintSatisfaction));71 return new (Mem) ASTConstraintSatisfaction(C, Satisfaction);72}73 74ASTConstraintSatisfaction *ASTConstraintSatisfaction::Rebuild(75 const ASTContext &C, const ASTConstraintSatisfaction &Satisfaction) {76 std::size_t size =77 totalSizeToAlloc<UnsatisfiedConstraintRecord>(Satisfaction.NumRecords);78 void *Mem = C.Allocate(size, alignof(ASTConstraintSatisfaction));79 return new (Mem) ASTConstraintSatisfaction(C, Satisfaction);80}81 82void ConstraintSatisfaction::Profile(llvm::FoldingSetNodeID &ID,83 const ASTContext &C,84 const NamedDecl *ConstraintOwner,85 ArrayRef<TemplateArgument> TemplateArgs) {86 ID.AddPointer(ConstraintOwner);87 ID.AddInteger(TemplateArgs.size());88 for (auto &Arg : TemplateArgs)89 Arg.Profile(ID, C);90}91 92ConceptReference *93ConceptReference::Create(const ASTContext &C, NestedNameSpecifierLoc NNS,94 SourceLocation TemplateKWLoc,95 DeclarationNameInfo ConceptNameInfo,96 NamedDecl *FoundDecl, TemplateDecl *NamedConcept,97 const ASTTemplateArgumentListInfo *ArgsAsWritten) {98 return new (C) ConceptReference(NNS, TemplateKWLoc, ConceptNameInfo,99 FoundDecl, NamedConcept, ArgsAsWritten);100}101 102SourceLocation ConceptReference::getBeginLoc() const {103 // Note that if the qualifier is null the template KW must also be null.104 if (auto QualifierLoc = getNestedNameSpecifierLoc())105 return QualifierLoc.getBeginLoc();106 return getConceptNameInfo().getBeginLoc();107}108 109void ConceptReference::print(llvm::raw_ostream &OS,110 const PrintingPolicy &Policy) const {111 NestedNameSpec.getNestedNameSpecifier().print(OS, Policy);112 ConceptName.printName(OS, Policy);113 if (hasExplicitTemplateArgs()) {114 OS << "<";115 llvm::ListSeparator Sep(", ");116 // FIXME: Find corresponding parameter for argument117 for (auto &ArgLoc : ArgsAsWritten->arguments()) {118 OS << Sep;119 ArgLoc.getArgument().print(Policy, OS, /*IncludeType*/ false);120 }121 OS << ">";122 }123}124 125const StreamingDiagnostic &clang::operator<<(const StreamingDiagnostic &DB,126 const ConceptReference *C) {127 std::string NameStr;128 llvm::raw_string_ostream OS(NameStr);129 LangOptions LO;130 LO.CPlusPlus = true;131 LO.Bool = true;132 OS << '\'';133 C->print(OS, PrintingPolicy(LO));134 OS << '\'';135 return DB << NameStr;136}137 138concepts::ExprRequirement::ExprRequirement(139 Expr *E, bool IsSimple, SourceLocation NoexceptLoc,140 ReturnTypeRequirement Req, SatisfactionStatus Status,141 ConceptSpecializationExpr *SubstitutedConstraintExpr)142 : Requirement(IsSimple ? RK_Simple : RK_Compound, Status == SS_Dependent,143 Status == SS_Dependent &&144 (E->containsUnexpandedParameterPack() ||145 Req.containsUnexpandedParameterPack()),146 Status == SS_Satisfied),147 Value(E), NoexceptLoc(NoexceptLoc), TypeReq(Req),148 SubstitutedConstraintExpr(SubstitutedConstraintExpr), Status(Status) {149 assert((!IsSimple || (Req.isEmpty() && NoexceptLoc.isInvalid())) &&150 "Simple requirement must not have a return type requirement or a "151 "noexcept specification");152 assert((Status > SS_TypeRequirementSubstitutionFailure &&153 Req.isTypeConstraint()) == (SubstitutedConstraintExpr != nullptr));154}155 156concepts::ExprRequirement::ExprRequirement(157 SubstitutionDiagnostic *ExprSubstDiag, bool IsSimple,158 SourceLocation NoexceptLoc, ReturnTypeRequirement Req)159 : Requirement(IsSimple ? RK_Simple : RK_Compound, Req.isDependent(),160 Req.containsUnexpandedParameterPack(), /*IsSatisfied=*/false),161 Value(ExprSubstDiag), NoexceptLoc(NoexceptLoc), TypeReq(Req),162 Status(SS_ExprSubstitutionFailure) {163 assert((!IsSimple || (Req.isEmpty() && NoexceptLoc.isInvalid())) &&164 "Simple requirement must not have a return type requirement or a "165 "noexcept specification");166}167 168concepts::ExprRequirement::ReturnTypeRequirement::ReturnTypeRequirement(169 TemplateParameterList *TPL)170 : TypeConstraintInfo(TPL, false) {171 assert(TPL->size() == 1);172 const TypeConstraint *TC =173 cast<TemplateTypeParmDecl>(TPL->getParam(0))->getTypeConstraint();174 assert(TC &&175 "TPL must have a template type parameter with a type constraint");176 auto *Constraint =177 cast<ConceptSpecializationExpr>(TC->getImmediatelyDeclaredConstraint());178 bool Dependent =179 Constraint->getTemplateArgsAsWritten() &&180 TemplateSpecializationType::anyInstantiationDependentTemplateArguments(181 Constraint->getTemplateArgsAsWritten()->arguments().drop_front(1));182 TypeConstraintInfo.setInt(Dependent ? true : false);183}184 185concepts::ExprRequirement::ReturnTypeRequirement::ReturnTypeRequirement(186 TemplateParameterList *TPL, bool IsDependent)187 : TypeConstraintInfo(TPL, IsDependent) {}188 189concepts::TypeRequirement::TypeRequirement(TypeSourceInfo *T)190 : Requirement(RK_Type, T->getType()->isInstantiationDependentType(),191 T->getType()->containsUnexpandedParameterPack(),192 // We reach this ctor with either dependent types (in which193 // IsSatisfied doesn't matter) or with non-dependent type in194 // which the existence of the type indicates satisfaction.195 /*IsSatisfied=*/true),196 Value(T),197 Status(T->getType()->isInstantiationDependentType() ? SS_Dependent198 : SS_Satisfied) {}199