Skip to content

Ast importer visitors #138838

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions clang/include/clang/AST/ExprConcepts.h
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,7 @@ class ExprRequirement : public Requirement {
// TODO: Can we maybe not save the whole template parameter list and just
// the type constraint? Saving the whole TPL makes it easier to handle in
// serialization but is less elegant.
ReturnTypeRequirement(TemplateParameterList *TPL, bool IsDependent);
ReturnTypeRequirement(TemplateParameterList *TPL);

bool isDependent() const {
Expand Down
21 changes: 21 additions & 0 deletions clang/include/clang/ASTMatchers/ASTMatchers.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprConcepts.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/LambdaCapture.h"
#include "clang/AST/NestedNameSpecifier.h"
Expand Down Expand Up @@ -1363,6 +1364,26 @@ extern const internal::VariadicDynCastAllOfMatcher<Decl, CXXDeductionGuideDecl>
extern const internal::VariadicDynCastAllOfMatcher<Decl, ConceptDecl>
conceptDecl;

/// Matches concept requirement.
///
/// Example matches 'requires(T p) { *p; }'
/// \code
/// template<typename T>
/// concept dereferencable = requires(T p) { *p; }
/// \endcode
extern const internal::VariadicDynCastAllOfMatcher<Expr, RequiresExpr>
requiresExpr;

/// Matches concept requirement body declaration.
///
/// Example matches '{ *p; }'
/// \code
/// template<typename T>
/// concept dereferencable = requires(T p) { *p; }
/// \endcode
extern const internal::VariadicDynCastAllOfMatcher<Decl, RequiresExprBodyDecl>
requiresExprBodyDecl;

/// Matches variable declarations.
///
/// Note: this does not match declarations of member variables, which are
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/AST/ASTConcept.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,10 @@ concepts::ExprRequirement::ReturnTypeRequirement::ReturnTypeRequirement(
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(),
Expand Down
287 changes: 287 additions & 0 deletions clang/lib/AST/ASTImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,17 @@ namespace clang {
Expected<InheritedConstructor>
ImportInheritedConstructor(const InheritedConstructor &From);

// Use for allocating string for newly imported object.
StringRef ImportASTStringRef(StringRef FromStr);
Error ImportConstraintSatisfaction(const ASTConstraintSatisfaction &FromSat,
ConstraintSatisfaction &ToSat);
Expected<concepts::Requirement *>
ImportTypeRequirement(concepts::TypeRequirement *From);
Expected<concepts::Requirement *>
ImportExprRequirement(concepts::ExprRequirement *From);
Expected<concepts::Requirement *>
ImportNestedRequirement(concepts::NestedRequirement *From);

template <typename T>
bool hasSameVisibilityContextAndLinkage(T *Found, T *From);

Expand Down Expand Up @@ -564,6 +575,9 @@ namespace clang {
ExpectedDecl VisitVarTemplateDecl(VarTemplateDecl *D);
ExpectedDecl VisitVarTemplateSpecializationDecl(VarTemplateSpecializationDecl *D);
ExpectedDecl VisitFunctionTemplateDecl(FunctionTemplateDecl *D);
ExpectedDecl VisitConceptDecl(ConceptDecl* D);
ExpectedDecl VisitRequiresExprBodyDecl(RequiresExprBodyDecl* E);
ExpectedDecl VisitImplicitConceptSpecializationDecl(ImplicitConceptSpecializationDecl* D);

// Importing statements
ExpectedStmt VisitStmt(Stmt *S);
Expand Down Expand Up @@ -680,6 +694,8 @@ namespace clang {
ExpectedStmt VisitTypeTraitExpr(TypeTraitExpr *E);
ExpectedStmt VisitCXXTypeidExpr(CXXTypeidExpr *E);
ExpectedStmt VisitCXXFoldExpr(CXXFoldExpr *E);
ExpectedStmt VisitRequiresExpr(RequiresExpr* E);
ExpectedStmt VisitConceptSpecializationExpr(ConceptSpecializationExpr* E);

// Helper for chaining together multiple imports. If an error is detected,
// subsequent imports will return default constructed nodes, so that failure
Expand Down Expand Up @@ -1039,6 +1055,177 @@ Expected<ConceptReference *> ASTNodeImporter::import(ConceptReference *From) {
return ConceptRef;
}

StringRef ASTNodeImporter::ImportASTStringRef(StringRef FromStr) {
char *ToStore = new (Importer.getToContext()) char[FromStr.size()];
std::copy(FromStr.begin(), FromStr.end(), ToStore);
return StringRef(ToStore, FromStr.size());
}

Error ASTNodeImporter::ImportConstraintSatisfaction(
const ASTConstraintSatisfaction &FromSat, ConstraintSatisfaction &ToSat) {
ToSat.IsSatisfied = FromSat.IsSatisfied;
ToSat.ContainsErrors = FromSat.ContainsErrors;
if (!ToSat.IsSatisfied) {
for (auto Record = FromSat.begin(); Record != FromSat.end(); ++Record) {
if (Expr *E = Record->dyn_cast<Expr *>()) {
ExpectedExpr ToSecondExpr = import(E);
if (!ToSecondExpr)
return ToSecondExpr.takeError();
ToSat.Details.emplace_back(ToSecondExpr.get());
} else {
auto Pair = Record->dyn_cast<std::pair<SourceLocation, StringRef> *>();

ExpectedSLoc ToPairFirst = import(Pair->first);
if (!ToPairFirst)
return ToPairFirst.takeError();
StringRef ToPairSecond = ImportASTStringRef(Pair->second);
ToSat.Details.emplace_back(
new (Importer.getToContext())
ConstraintSatisfaction::SubstitutionDiagnostic{
ToPairFirst.get(), ToPairSecond});
}
}
}
return Error::success();
}

template <>
Expected<concepts::Requirement::SubstitutionDiagnostic *>
ASTNodeImporter::import(
concepts::Requirement::SubstitutionDiagnostic *FromDiag) {
StringRef ToEntity = ImportASTStringRef(FromDiag->SubstitutedEntity);
ExpectedSLoc ToLoc = import(FromDiag->DiagLoc);
if (!ToLoc)
return ToLoc.takeError();
StringRef ToDiagMessage = ImportASTStringRef(FromDiag->DiagMessage);
return new (Importer.getToContext())
concepts::Requirement::SubstitutionDiagnostic{ToEntity, ToLoc.get(),
ToDiagMessage};
}

Expected<concepts::Requirement *>
ASTNodeImporter::ImportTypeRequirement(concepts::TypeRequirement *From) {
using namespace concepts;

if (From->isSubstitutionFailure()) {
auto DiagOrErr = import(From->getSubstitutionDiagnostic());
if (!DiagOrErr)
return DiagOrErr.takeError();
return new (Importer.getToContext()) TypeRequirement(*DiagOrErr);
} else {
Expected<TypeSourceInfo *> ToType = import(From->getType());
if (!ToType)
return ToType.takeError();
return new (Importer.getToContext()) TypeRequirement(*ToType);
}
}

Expected<concepts::Requirement *>
ASTNodeImporter::ImportExprRequirement(concepts::ExprRequirement *From) {
using namespace concepts;

bool IsRKSimple = From->getKind() == Requirement::RK_Simple;
ExprRequirement::SatisfactionStatus Status = From->getSatisfactionStatus();

std::optional<ExprRequirement::ReturnTypeRequirement> Req;
ConceptSpecializationExpr *SubstitutedConstraintExpr = nullptr;

if (IsRKSimple) {
Req.emplace();
} else {
const ExprRequirement::ReturnTypeRequirement &FromTypeRequirement =
From->getReturnTypeRequirement();

if (FromTypeRequirement.isTypeConstraint()) {
const bool IsDependent = FromTypeRequirement.isDependent();
auto ParamsOrErr =
import(FromTypeRequirement.getTypeConstraintTemplateParameterList());
if (!ParamsOrErr)
return ParamsOrErr.takeError();
if (Status >= ExprRequirement::SS_ConstraintsNotSatisfied) {
auto SubstConstraintExprOrErr =
import(From->getReturnTypeRequirementSubstitutedConstraintExpr());
if (!SubstConstraintExprOrErr)
return SubstConstraintExprOrErr.takeError();
SubstitutedConstraintExpr = SubstConstraintExprOrErr.get();
}
Req.emplace(ParamsOrErr.get(), IsDependent);
} else if (FromTypeRequirement.isSubstitutionFailure()) {
auto DiagOrErr = import(FromTypeRequirement.getSubstitutionDiagnostic());
if (!DiagOrErr)
return DiagOrErr.takeError();
Req.emplace(DiagOrErr.get());
} else {
Req.emplace();
}
}

ExpectedSLoc NoexceptLocOrErr = import(From->getNoexceptLoc());
if (!NoexceptLocOrErr)
return NoexceptLocOrErr.takeError();

if (Status == ExprRequirement::SS_ExprSubstitutionFailure) {
auto DiagOrErr = import(From->getExprSubstitutionDiagnostic());
if (!DiagOrErr)
return DiagOrErr.takeError();
return new (Importer.getToContext()) ExprRequirement(
*DiagOrErr, IsRKSimple, *NoexceptLocOrErr, std::move(*Req));
} else {
Expected<Expr *> ExprOrErr = import(From->getExpr());
if (!ExprOrErr)
return ExprOrErr.takeError();
return new (Importer.getToContext()) concepts::ExprRequirement(
*ExprOrErr, IsRKSimple, *NoexceptLocOrErr, std::move(*Req), Status,
SubstitutedConstraintExpr);
}
}

Expected<concepts::Requirement *>
ASTNodeImporter::ImportNestedRequirement(concepts::NestedRequirement *From) {
using namespace concepts;

const ASTConstraintSatisfaction &FromSatisfaction =
From->getConstraintSatisfaction();
if (From->hasInvalidConstraint()) {
StringRef ToEntity = ImportASTStringRef(From->getInvalidConstraintEntity());
ASTConstraintSatisfaction *ToSatisfaction =
ASTConstraintSatisfaction::Rebuild(Importer.getToContext(),
FromSatisfaction);
return new (Importer.getToContext())
NestedRequirement(ToEntity, ToSatisfaction);
} else {
ExpectedExpr ToExpr = import(From->getConstraintExpr());
if (!ToExpr)
return ToExpr.takeError();
if (ToExpr.get()->isInstantiationDependent()) {
return new (Importer.getToContext()) NestedRequirement(ToExpr.get());
} else {
ConstraintSatisfaction Satisfaction;
if (Error Err =
ImportConstraintSatisfaction(FromSatisfaction, Satisfaction))
return std::move(Err);
return new (Importer.getToContext()) NestedRequirement(
Importer.getToContext(), ToExpr.get(), Satisfaction);
}
}
}

template <>
Expected<concepts::Requirement *>
ASTNodeImporter::import(concepts::Requirement *FromRequire) {
switch (FromRequire->getKind()) {
case concepts::Requirement::RequirementKind::RK_Type:
return ImportTypeRequirement(cast<concepts::TypeRequirement>(FromRequire));
case concepts::Requirement::RequirementKind::RK_Compound:
case concepts::Requirement::RequirementKind::RK_Simple:
return ImportExprRequirement(cast<concepts::ExprRequirement>(FromRequire));
case concepts::Requirement::RequirementKind::RK_Nested:
return ImportNestedRequirement(
cast<concepts::NestedRequirement>(FromRequire));
}
llvm_unreachable("Unhandled requirement kind");
}

template <>
Expected<LambdaCapture> ASTNodeImporter::import(const LambdaCapture &From) {
ValueDecl *Var = nullptr;
Expand Down Expand Up @@ -6835,6 +7022,62 @@ ASTNodeImporter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
return ToFunc;
}

ExpectedDecl ASTNodeImporter::VisitConceptDecl(ConceptDecl *D) {
DeclContext *DC, *LexicalDC;
Error Err = ImportDeclContext(D, DC, LexicalDC);
auto LocationOrErr = importChecked(Err, D->getLocation());
auto NameDeclOrErr = importChecked(Err, D->getDeclName());
auto ToTemplateParameters = importChecked(Err, D->getTemplateParameters());
auto ConstraintExpr = importChecked(Err, D->getConstraintExpr());
if (Err)
return std::move(Err);

ConceptDecl *To;
if (GetImportedOrCreateDecl(To, D, Importer.getToContext(), DC, LocationOrErr,
NameDeclOrErr, ToTemplateParameters,
ConstraintExpr))
return To;
To->setLexicalDeclContext(LexicalDC);
LexicalDC->addDeclInternal(To);
return To;
}

ExpectedDecl
ASTNodeImporter::VisitRequiresExprBodyDecl(RequiresExprBodyDecl *D) {
DeclContext *DC, *LexicalDC;
Error Err = ImportDeclContext(D, DC, LexicalDC);
auto RequiresLoc = importChecked(Err, D->getLocation());
if (Err)
return std::move(Err);

RequiresExprBodyDecl *To;
if (GetImportedOrCreateDecl(To, D, Importer.getToContext(), DC, RequiresLoc))
return To;
To->setLexicalDeclContext(LexicalDC);
LexicalDC->addDeclInternal(To);
return To;
}

ExpectedDecl ASTNodeImporter::VisitImplicitConceptSpecializationDecl(
ImplicitConceptSpecializationDecl *D) {
DeclContext *DC, *LexicalDC;
Error Err = ImportDeclContext(D, DC, LexicalDC);
auto ToSL = importChecked(Err, D->getLocation());
if (Err)
return std::move(Err);

SmallVector<TemplateArgument, 2> ToArgs(D->getTemplateArguments().size());
if (Error Err = ImportTemplateArguments(D->getTemplateArguments(), ToArgs))
return std::move(Err);

ImplicitConceptSpecializationDecl *To;
if (GetImportedOrCreateDecl(To, D, Importer.getToContext(), DC, ToSL, ToArgs))
return To;
To->setLexicalDeclContext(LexicalDC);
LexicalDC->addDeclInternal(To);
return To;
}

//----------------------------------------------------------------------------
// Import Statements
//----------------------------------------------------------------------------
Expand Down Expand Up @@ -9054,6 +9297,50 @@ ExpectedStmt ASTNodeImporter::VisitCXXFoldExpr(CXXFoldExpr *E) {
ToEllipsisLoc, ToRHS, ToRParenLoc, E->getNumExpansions());
}

ExpectedStmt ASTNodeImporter::VisitRequiresExpr(RequiresExpr *E) {
Error Err = Error::success();
auto RequiresKWLoc = importChecked(Err, E->getRequiresKWLoc());
auto RParenLoc = importChecked(Err, E->getRParenLoc());
auto RBraceLoc = importChecked(Err, E->getRBraceLoc());

auto Body = importChecked(Err, E->getBody());
auto LParenLoc = importChecked(Err, E->getLParenLoc());
if (Err)
return std::move(Err);
SmallVector<ParmVarDecl *, 4> LocalParameters(E->getLocalParameters().size());
if (Error Err =
ImportArrayChecked(E->getLocalParameters(), LocalParameters.begin()))
return std::move(Err);
SmallVector<concepts::Requirement *, 4> Requirements(
E->getRequirements().size());
if (Error Err =
ImportArrayChecked(E->getRequirements(), Requirements.begin()))
return std::move(Err);
return RequiresExpr::Create(Importer.getToContext(), RequiresKWLoc, Body,
LParenLoc, LocalParameters, RParenLoc,
Requirements, RBraceLoc);
}

ExpectedStmt
ASTNodeImporter::VisitConceptSpecializationExpr(ConceptSpecializationExpr *E) {
Error Err = Error::success();
auto CL = importChecked(Err, E->getConceptReference());
auto CSD = importChecked(Err, E->getSpecializationDecl());
if (Err)
return std::move(Err);
if (E->isValueDependent())
return ConceptSpecializationExpr::Create(
Importer.getToContext(), CL,
const_cast<ImplicitConceptSpecializationDecl *>(CSD), nullptr);
ConstraintSatisfaction Satisfaction;
if (Error Err =
ImportConstraintSatisfaction(E->getSatisfaction(), Satisfaction))
return std::move(Err);
return ConceptSpecializationExpr::Create(
Importer.getToContext(), CL,
const_cast<ImplicitConceptSpecializationDecl *>(CSD), &Satisfaction);
}

Error ASTNodeImporter::ImportOverriddenMethods(CXXMethodDecl *ToMethod,
CXXMethodDecl *FromMethod) {
Error ImportErrors = Error::success();
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/AST/ASTStructuralEquivalence.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1609,6 +1609,11 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
CXXMethodDecl *Method1,
CXXMethodDecl *Method2) {
if (!Method1 && !Method2)
return true;
if (!Method1 || !Method2)
return false;

bool PropertiesEqual =
Method1->getDeclKind() == Method2->getDeclKind() &&
Method1->getRefQualifier() == Method2->getRefQualifier() &&
Expand Down
Loading