| //===--- ASTConcept.cpp - Concepts Related AST Data Structures --*- C++ -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| /// |
| /// \file |
| /// \brief This file defines AST data structures related to concepts. |
| /// |
| //===----------------------------------------------------------------------===// |
| |
| #include "clang/AST/ASTConcept.h" |
| #include "clang/AST/ASTContext.h" |
| #include "clang/AST/ExprConcepts.h" |
| #include "clang/AST/NestedNameSpecifier.h" |
| #include "clang/AST/PrettyPrinter.h" |
| #include "llvm/ADT/StringExtras.h" |
| |
| using namespace clang; |
| |
| static void |
| CreateUnsatisfiedConstraintRecord(const ASTContext &C, |
| const UnsatisfiedConstraintRecord &Detail, |
| UnsatisfiedConstraintRecord *TrailingObject) { |
| if (auto *E = dyn_cast<Expr *>(Detail)) |
| new (TrailingObject) UnsatisfiedConstraintRecord(E); |
| else { |
| auto &SubstitutionDiagnostic = |
| *cast<std::pair<SourceLocation, StringRef> *>(Detail); |
| StringRef Message = C.backupStr(SubstitutionDiagnostic.second); |
| auto *NewSubstDiag = new (C) std::pair<SourceLocation, StringRef>( |
| SubstitutionDiagnostic.first, Message); |
| new (TrailingObject) UnsatisfiedConstraintRecord(NewSubstDiag); |
| } |
| } |
| |
| ASTConstraintSatisfaction::ASTConstraintSatisfaction( |
| const ASTContext &C, const ConstraintSatisfaction &Satisfaction) |
| : NumRecords{Satisfaction.Details.size()}, |
| IsSatisfied{Satisfaction.IsSatisfied}, ContainsErrors{ |
| Satisfaction.ContainsErrors} { |
| for (unsigned I = 0; I < NumRecords; ++I) |
| CreateUnsatisfiedConstraintRecord(C, Satisfaction.Details[I], |
| getTrailingObjects() + I); |
| } |
| |
| ASTConstraintSatisfaction::ASTConstraintSatisfaction( |
| const ASTContext &C, const ASTConstraintSatisfaction &Satisfaction) |
| : NumRecords{Satisfaction.NumRecords}, |
| IsSatisfied{Satisfaction.IsSatisfied}, |
| ContainsErrors{Satisfaction.ContainsErrors} { |
| for (unsigned I = 0; I < NumRecords; ++I) |
| CreateUnsatisfiedConstraintRecord(C, *(Satisfaction.begin() + I), |
| getTrailingObjects() + I); |
| } |
| |
| ASTConstraintSatisfaction * |
| ASTConstraintSatisfaction::Create(const ASTContext &C, |
| const ConstraintSatisfaction &Satisfaction) { |
| std::size_t size = |
| totalSizeToAlloc<UnsatisfiedConstraintRecord>( |
| Satisfaction.Details.size()); |
| void *Mem = C.Allocate(size, alignof(ASTConstraintSatisfaction)); |
| return new (Mem) ASTConstraintSatisfaction(C, Satisfaction); |
| } |
| |
| ASTConstraintSatisfaction *ASTConstraintSatisfaction::Rebuild( |
| const ASTContext &C, const ASTConstraintSatisfaction &Satisfaction) { |
| std::size_t size = |
| totalSizeToAlloc<UnsatisfiedConstraintRecord>(Satisfaction.NumRecords); |
| void *Mem = C.Allocate(size, alignof(ASTConstraintSatisfaction)); |
| return new (Mem) ASTConstraintSatisfaction(C, Satisfaction); |
| } |
| |
| void ConstraintSatisfaction::Profile( |
| llvm::FoldingSetNodeID &ID, const ASTContext &C, |
| const NamedDecl *ConstraintOwner, ArrayRef<TemplateArgument> TemplateArgs) { |
| ID.AddPointer(ConstraintOwner); |
| ID.AddInteger(TemplateArgs.size()); |
| for (auto &Arg : TemplateArgs) |
| Arg.Profile(ID, C); |
| } |
| |
| ConceptReference * |
| ConceptReference::Create(const ASTContext &C, NestedNameSpecifierLoc NNS, |
| SourceLocation TemplateKWLoc, |
| DeclarationNameInfo ConceptNameInfo, |
| NamedDecl *FoundDecl, TemplateDecl *NamedConcept, |
| const ASTTemplateArgumentListInfo *ArgsAsWritten) { |
| return new (C) ConceptReference(NNS, TemplateKWLoc, ConceptNameInfo, |
| FoundDecl, NamedConcept, ArgsAsWritten); |
| } |
| |
| SourceLocation ConceptReference::getBeginLoc() const { |
| // Note that if the qualifier is null the template KW must also be null. |
| if (auto QualifierLoc = getNestedNameSpecifierLoc()) |
| return QualifierLoc.getBeginLoc(); |
| return getConceptNameInfo().getBeginLoc(); |
| } |
| |
| void ConceptReference::print(llvm::raw_ostream &OS, |
| const PrintingPolicy &Policy) const { |
| NestedNameSpec.getNestedNameSpecifier().print(OS, Policy); |
| ConceptName.printName(OS, Policy); |
| if (hasExplicitTemplateArgs()) { |
| OS << "<"; |
| llvm::ListSeparator Sep(", "); |
| // FIXME: Find corresponding parameter for argument |
| for (auto &ArgLoc : ArgsAsWritten->arguments()) { |
| OS << Sep; |
| ArgLoc.getArgument().print(Policy, OS, /*IncludeType*/ false); |
| } |
| OS << ">"; |
| } |
| } |
| |
| concepts::ExprRequirement::ExprRequirement( |
| Expr *E, bool IsSimple, SourceLocation NoexceptLoc, |
| ReturnTypeRequirement Req, SatisfactionStatus Status, |
| ConceptSpecializationExpr *SubstitutedConstraintExpr) |
| : Requirement(IsSimple ? RK_Simple : RK_Compound, Status == SS_Dependent, |
| Status == SS_Dependent && |
| (E->containsUnexpandedParameterPack() || |
| Req.containsUnexpandedParameterPack()), |
| Status == SS_Satisfied), |
| Value(E), NoexceptLoc(NoexceptLoc), TypeReq(Req), |
| SubstitutedConstraintExpr(SubstitutedConstraintExpr), Status(Status) { |
| assert((!IsSimple || (Req.isEmpty() && NoexceptLoc.isInvalid())) && |
| "Simple requirement must not have a return type requirement or a " |
| "noexcept specification"); |
| assert((Status > SS_TypeRequirementSubstitutionFailure && |
| Req.isTypeConstraint()) == (SubstitutedConstraintExpr != nullptr)); |
| } |
| |
| concepts::ExprRequirement::ExprRequirement( |
| SubstitutionDiagnostic *ExprSubstDiag, bool IsSimple, |
| SourceLocation NoexceptLoc, ReturnTypeRequirement Req) |
| : Requirement(IsSimple ? RK_Simple : RK_Compound, Req.isDependent(), |
| Req.containsUnexpandedParameterPack(), /*IsSatisfied=*/false), |
| Value(ExprSubstDiag), NoexceptLoc(NoexceptLoc), TypeReq(Req), |
| Status(SS_ExprSubstitutionFailure) { |
| assert((!IsSimple || (Req.isEmpty() && NoexceptLoc.isInvalid())) && |
| "Simple requirement must not have a return type requirement or a " |
| "noexcept specification"); |
| } |
| |
| concepts::ExprRequirement::ReturnTypeRequirement::ReturnTypeRequirement( |
| TemplateParameterList *TPL) |
| : TypeConstraintInfo(TPL, false) { |
| assert(TPL->size() == 1); |
| const TypeConstraint *TC = |
| cast<TemplateTypeParmDecl>(TPL->getParam(0))->getTypeConstraint(); |
| assert(TC && |
| "TPL must have a template type parameter with a type constraint"); |
| auto *Constraint = |
| cast<ConceptSpecializationExpr>(TC->getImmediatelyDeclaredConstraint()); |
| bool Dependent = |
| Constraint->getTemplateArgsAsWritten() && |
| TemplateSpecializationType::anyInstantiationDependentTemplateArguments( |
| Constraint->getTemplateArgsAsWritten()->arguments().drop_front(1)); |
| TypeConstraintInfo.setInt(Dependent ? true : false); |
| } |
| |
| concepts::ExprRequirement::ReturnTypeRequirement::ReturnTypeRequirement( |
| TemplateParameterList *TPL, bool IsDependent) |
| : TypeConstraintInfo(TPL, IsDependent) {} |
| |
| concepts::TypeRequirement::TypeRequirement(TypeSourceInfo *T) |
| : Requirement(RK_Type, T->getType()->isInstantiationDependentType(), |
| T->getType()->containsUnexpandedParameterPack(), |
| // We reach this ctor with either dependent types (in which |
| // IsSatisfied doesn't matter) or with non-dependent type in |
| // which the existence of the type indicates satisfaction. |
| /*IsSatisfied=*/true), |
| Value(T), |
| Status(T->getType()->isInstantiationDependentType() ? SS_Dependent |
| : SS_Satisfied) {} |