llvm-project/clang/lib/AST/ASTConcept.cpp
2025-05-22 21:57:45 +02:00

169 lines
7.3 KiB
C++

//===--- 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/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, ConceptDecl *NamedConcept,
const ASTTemplateArgumentListInfo *ArgsAsWritten) {
return new (C) ConceptReference(NNS, TemplateKWLoc, ConceptNameInfo,
FoundDecl, NamedConcept, ArgsAsWritten);
}
void ConceptReference::print(llvm::raw_ostream &OS,
const PrintingPolicy &Policy) const {
if (NestedNameSpec)
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::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) {}