https://github.com/ganenkokb-yandex updated https://github.com/llvm/llvm-project/pull/138838
>From 6a4d62ce1c72639d7fe82565744b3e8808dce4c3 Mon Sep 17 00:00:00 2001 From: Evianaive <153540...@qq.com> Date: Tue, 25 Mar 2025 01:54:06 +0800 Subject: [PATCH 01/18] Implement missing visit function --- clang/lib/AST/ASTImporter.cpp | 285 +++++++++++++++++++++++++++++++++- 1 file changed, 284 insertions(+), 1 deletion(-) diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 5c44353d8b987..d8767a48ad27d 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -68,6 +68,7 @@ #include <optional> #include <type_traits> #include <utility> +#include "ExprConcepts.h" namespace clang { @@ -564,6 +565,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); @@ -680,6 +684,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 @@ -1063,6 +1069,168 @@ Expected<LambdaCapture> ASTNodeImporter::import(const LambdaCapture &From) { EllipsisLoc); } +template<> +Expected<concepts::Requirement*> ASTNodeImporter::import(concepts::Requirement* FromRequire) { + auto ImportStringRef = [this](const StringRef& FromString) { + char* ToDiagMessage = new (Importer.getToContext()) char[FromString.size()]; + std::copy(FromString.begin(),FromString.end(),ToDiagMessage); + return StringRef(ToDiagMessage,FromString.size()); + }; + + auto ImportSubstitutionDiagnos = [this, &ImportStringRef] + (concepts::Requirement::SubstitutionDiagnostic* FromDiagnos, Error& Err)->concepts::Requirement::SubstitutionDiagnostic* { + const auto& ToEntity = ImportStringRef(FromDiagnos->SubstitutedEntity); + Expected<SourceLocation> ToLoc = import(FromDiagnos->DiagLoc); + if(!ToLoc) { + Err = ToLoc.takeError(); + return nullptr; + } + const auto& ToDiagMessage = ImportStringRef(FromDiagnos->DiagMessage); + return new (Importer.getToContext()) concepts::Requirement::SubstitutionDiagnostic{ + ToEntity, + ToLoc.get(), + ToDiagMessage}; + }; + switch (FromRequire->getKind()) { + case concepts::Requirement::RequirementKind::RK_Type: { + auto *From = cast<concepts::TypeRequirement>(FromRequire); + if(From->isSubstitutionFailure()) + { + // Should we return Error directly if TypeRequirement isSubstitutionFailure? + Error Err = Error::success(); + auto Diagnos = ImportSubstitutionDiagnos(From->getSubstitutionDiagnostic(),Err); + if (Err) + return std::move(Err); + return new (Importer.getToContext()) concepts::TypeRequirement(Diagnos); + } + else { + Expected<TypeSourceInfo *> ToType = import(From->getType()); + if(!ToType) + return ToType.takeError(); + return new (Importer.getToContext()) concepts::TypeRequirement(ToType.get()); + } + break; + } + case concepts::Requirement::RequirementKind::RK_Compound: + case concepts::Requirement::RequirementKind::RK_Simple: { + const auto *From = cast<concepts::ExprRequirement>(FromRequire); + + auto Status = From->getSatisfactionStatus(); + llvm::PointerUnion<concepts::Requirement::SubstitutionDiagnostic *, Expr *> E; + if (Status == concepts::ExprRequirement::SS_ExprSubstitutionFailure) { + Error Err = Error::success(); + E = ImportSubstitutionDiagnos(From->getExprSubstitutionDiagnostic(),Err); + if (Err) + return std::move(Err); + } else { + auto ExpectE = import(From->getExpr()); + if (!ExpectE) + return ExpectE.takeError(); + E = ExpectE.get(); + } + + std::optional<concepts::ExprRequirement::ReturnTypeRequirement> Req; + ConceptSpecializationExpr *SubstitutedConstraintExpr = nullptr; + SourceLocation NoexceptLoc; + bool IsRKSimple = FromRequire->getKind() == concepts::Requirement::RK_Simple; + if (IsRKSimple) { + Req.emplace(); + } else { + auto NoexceptLoc = import(From->getNoexceptLoc()); + if(!NoexceptLoc) + return NoexceptLoc.takeError(); + auto& FromTypeRequirement = From->getReturnTypeRequirement(); + + if(FromTypeRequirement.isTypeConstraint()) { + auto ParamsOrErr = import(FromTypeRequirement.getTypeConstraintTemplateParameterList()); + if (!ParamsOrErr) + return ParamsOrErr.takeError(); + if (Status >= + concepts::ExprRequirement::SS_ConstraintsNotSatisfied) { + auto ExpectSubstitutedConstraintExpr = import(From->getReturnTypeRequirementSubstitutedConstraintExpr()); + if (!ExpectSubstitutedConstraintExpr) + return ExpectSubstitutedConstraintExpr.takeError(); + SubstitutedConstraintExpr = ExpectSubstitutedConstraintExpr.get(); + } + Req.emplace(ParamsOrErr.get()); + } + else if(FromTypeRequirement.isSubstitutionFailure()) { + Error Err = Error::success(); + concepts::Requirement::SubstitutionDiagnostic *ToDiagnos = + ImportSubstitutionDiagnos( + FromTypeRequirement.getSubstitutionDiagnostic(), Err); + if (Err) + return std::move(Err); + Req.emplace(ToDiagnos); + } + else { + Req.emplace(); + } + } + if (Expr *Ex = E.dyn_cast<Expr *>()) + return new (Importer.getToContext()) concepts::ExprRequirement( + Ex, IsRKSimple, NoexceptLoc, + std::move(*Req), Status, SubstitutedConstraintExpr); + else + return new (Importer.getToContext()) concepts::ExprRequirement( + E.get<concepts::Requirement::SubstitutionDiagnostic *>(), + IsRKSimple, NoexceptLoc, + std::move(*Req)); + break; + } + case concepts::Requirement::RequirementKind::RK_Nested: { + auto *From = cast<concepts::NestedRequirement>(FromRequire); + const auto& FromSatisfaction = From->getConstraintSatisfaction(); + if(From->hasInvalidConstraint()) { + const auto& ToConstraintEntity = ImportStringRef(From->getInvalidConstraintEntity()); + auto ToSatisfaction = ASTConstraintSatisfaction::Rebuild(Importer.getToContext(),FromSatisfaction); + return new (Importer.getToContext()) concepts::NestedRequirement(ToConstraintEntity,ToSatisfaction); + } else { + Expected<Expr *> ToExpr = import(From->getConstraintExpr()); + if(!ToExpr) + return ToExpr.takeError(); + // FromSatisfaction.IsSatisfied; + if(ToExpr.get()->isInstantiationDependent()) + return new (Importer.getToContext()) concepts::NestedRequirement(ToExpr.get()); + else { + ConstraintSatisfaction Satisfaction; + Satisfaction.IsSatisfied = FromSatisfaction.IsSatisfied; + Satisfaction.ContainsErrors = FromSatisfaction.ContainsErrors; + if (!Satisfaction.IsSatisfied) { + for (auto Record = FromSatisfaction.begin(); Record != FromSatisfaction.end(); ++Record) { + const Expr *ConstraintExpr = Record->first; + Expected<Expr *> ToConstraintExpr = import(ConstraintExpr); + if(!ToConstraintExpr) + return ToConstraintExpr.takeError(); + if(Record->second.is<Expr*>()) { + Expected<Expr *> ToSecondExpr = import(Record->second.get<Expr*>()); + if(!ToSecondExpr) + return ToSecondExpr.takeError(); + Satisfaction.Details.emplace_back(ToConstraintExpr.get(),ToSecondExpr.get()); + } else { + std::pair<SourceLocation, StringRef> *pair = Record->second.get< + std::pair<SourceLocation, StringRef> *>(); + Error Err = Error::success(); + + auto ToPairFirst = import(pair->first); + if(!ToPairFirst) + return ToPairFirst.takeError(); + StringRef ToPairSecond = ImportStringRef(pair->second); + Satisfaction.Details.emplace_back( + ToConstraintExpr.get(), new (Importer.getToContext()) + ConstraintSatisfaction::SubstitutionDiagnostic{ + ToPairFirst.get(), ToPairSecond}); + } + } + } + return new (Importer.getToContext()) concepts::NestedRequirement(Importer.getToContext(),ToExpr.get(),Satisfaction); + } + } + break; + } + } +} + template <typename T> bool ASTNodeImporter::hasSameVisibilityContextAndLinkage(T *Found, T *From) { if (Found->getLinkageInternal() != From->getLinkageInternal()) @@ -7359,6 +7527,121 @@ ExpectedStmt ASTNodeImporter::VisitExpr(Expr *E) { return make_error<ASTImportError>(ASTImportError::UnsupportedConstruct); } +ExpectedStmt ASTNodeImporter::VisitRequiresExpr(RequiresExpr* E) { + Error Err = Error::success(); + // auto ToType = importChecked(Err, E->getType()); + 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; + if (Error Err = ImportArrayChecked(E->getLocalParameters(),LocalParameters.begin())) + return std::move(Err); + SmallVector<concepts::Requirement*, 4> Requirements; + if (Error Err = ImportArrayChecked(E->getRequirements(),Requirements.begin())) + return std::move(Err); + return RequiresExpr::Create(Importer.getToContext(),RequiresKWLoc, Body, LParenLoc, + LocalParameters, RParenLoc, Requirements, RBraceLoc); +} + +ExpectedDecl ASTNodeImporter::VisitRequiresExprBodyDecl(RequiresExprBodyDecl* D) { + DeclContext *DC, *LexicalDC; + Error Err = Error::success(); + Err = ImportDeclContext(D, DC, LexicalDC); + auto RequiresLoc = importChecked(Err,D->getLocation()); + return RequiresExprBodyDecl::Create(Importer.getToContext(),DC,RequiresLoc); +} + +ExpectedStmt ASTNodeImporter::VisitConceptSpecializationExpr(ConceptSpecializationExpr* E) { + Error Err = Error::success(); + + auto CL = importChecked(Err,E->getConceptReference()); + auto CSD = importChecked(Err,E->getSpecializationDecl()); + // auto Satisfaction = importChecked(Err,E->getSatisfaction()); + if (Err) + return std::move(Err); + // E->getDependence(); + if(E->isValueDependent()) { + return ConceptSpecializationExpr::Create( + Importer.getToContext(), CL, + const_cast<ImplicitConceptSpecializationDecl *>(CSD), nullptr); + } + const auto& FromSatisfaction = E->getSatisfaction(); + auto ImportStringRef = [this](const StringRef& FromString) { + char* ToDiagMessage = new (Importer.getToContext()) char[FromString.size()]; + std::copy(FromString.begin(),FromString.end(),ToDiagMessage); + return StringRef(ToDiagMessage,FromString.size()); + }; + ConstraintSatisfaction Satisfaction; + Satisfaction.IsSatisfied = FromSatisfaction.IsSatisfied; + Satisfaction.ContainsErrors = FromSatisfaction.ContainsErrors; + if (!Satisfaction.IsSatisfied) { + for (auto Record = FromSatisfaction.begin(); Record != FromSatisfaction.end(); ++Record) { + const Expr *ConstraintExpr = Record->first; + Expected<Expr *> ToConstraintExpr = import(ConstraintExpr); + if(!ToConstraintExpr) + return ToConstraintExpr.takeError(); + if(Record->second.is<Expr*>()) { + Expected<Expr *> ToSecondExpr = import(Record->second.get<Expr*>()); + if(!ToSecondExpr) + return ToSecondExpr.takeError(); + Satisfaction.Details.emplace_back(ToConstraintExpr.get(),ToSecondExpr.get()); + } else { + std::pair<SourceLocation, StringRef> *pair = Record->second.get< + std::pair<SourceLocation, StringRef> *>(); + Error Err = Error::success(); + + auto ToPairFirst = import(pair->first); + if(!ToPairFirst) + return ToPairFirst.takeError(); + StringRef ToPairSecond = ImportStringRef(pair->second); + Satisfaction.Details.emplace_back( + ToConstraintExpr.get(), new(Importer.getToContext()) ConstraintSatisfaction::SubstitutionDiagnostic{ + ToPairFirst.get(), ToPairSecond}); + } + } + } + return ConceptSpecializationExpr::Create( + Importer.getToContext(), CL, + const_cast<ImplicitConceptSpecializationDecl *>(CSD), &Satisfaction); +} + +ExpectedDecl ASTNodeImporter::VisitConceptDecl(ConceptDecl* D) { + // Import the context of this declaration. + DeclContext *DC, *LexicalDC; + Error Err = Error::success(); + Err = ImportDeclContext(D, DC, LexicalDC); + auto BeginLocOrErr = importChecked(Err, D->getBeginLoc()); + 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); + return ConceptDecl::Create( + Importer.getToContext(),DC, + LocationOrErr,NameDeclOrErr, + ToTemplateParameters,ConstraintExpr); +} + +ExpectedDecl ASTNodeImporter::VisitImplicitConceptSpecializationDecl(ImplicitConceptSpecializationDecl* D) { + DeclContext *DC, *LexicalDC; + Error Err = Error::success(); + Err = ImportDeclContext(D, DC, LexicalDC); + auto ToSL = importChecked(Err,D->getLocation()); + if(Err) + return std::move(Err); + SmallVector<TemplateArgument,2> ToArgs; + if(Error Err = ImportTemplateArguments(D->getTemplateArguments(),ToArgs)) + return std::move(Err); + + return ImplicitConceptSpecializationDecl::Create(Importer.getToContext(),DC,ToSL,ToArgs); +} + ExpectedStmt ASTNodeImporter::VisitSourceLocExpr(SourceLocExpr *E) { Error Err = Error::success(); auto ToType = importChecked(Err, E->getType()); @@ -10585,4 +10868,4 @@ bool ASTImporter::IsStructurallyEquivalent(QualType From, QualType To, getToContext().getLangOpts(), FromContext, ToContext, NonEquivalentDecls, getStructuralEquivalenceKind(*this), false, Complain); return Ctx.IsEquivalent(From, To); -} +} \ No newline at end of file >From 6e0dd2f2eab9a89946247f7988454e1f26202f5a Mon Sep 17 00:00:00 2001 From: Konstantin Ganenko <ganenk...@yandex-team.ru> Date: Tue, 6 May 2025 18:36:49 +0300 Subject: [PATCH 02/18] Fix patch compilation --- clang/lib/AST/ASTImporter.cpp | 102 ++++++++++++++-------------------- 1 file changed, 42 insertions(+), 60 deletions(-) diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index d8767a48ad27d..f75326079d0f9 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -68,7 +68,6 @@ #include <optional> #include <type_traits> #include <utility> -#include "ExprConcepts.h" namespace clang { @@ -741,6 +740,40 @@ namespace clang { // that type is declared inside the body of the function. // E.g. auto f() { struct X{}; return X(); } bool hasReturnTypeDeclaredInside(FunctionDecl *D); + + Expected<ConstraintSatisfaction> FillConstraintSatisfaction(const ASTConstraintSatisfaction& from) { + auto ImportStringRef = [this](const StringRef& FromString) { + char* ToDiagMessage = new (Importer.getToContext()) char[FromString.size()]; + std::copy(FromString.begin(),FromString.end(),ToDiagMessage); + return StringRef(ToDiagMessage,FromString.size()); + }; + ConstraintSatisfaction Satisfaction; + Satisfaction.IsSatisfied = from.IsSatisfied; + Satisfaction.ContainsErrors = from.ContainsErrors; + if (!Satisfaction.IsSatisfied) { + using SubstitutionDiagnostic = std::pair<SourceLocation, StringRef>; + for (auto &Record : from) { + if (auto *SubstDiag = Record.dyn_cast<SubstitutionDiagnostic *>()) { + Error Err = Error::success(); + + auto ToPairFirst = import(SubstDiag->first); + if(!ToPairFirst) + return ToPairFirst.takeError(); + StringRef ToPairSecond = ImportStringRef(SubstDiag->second); + Satisfaction.Details.emplace_back(new (Importer.getToContext()) + ConstraintSatisfaction::SubstitutionDiagnostic{ + ToPairFirst.get(), ToPairSecond}); + } else { + const Expr *ConstraintExpr = Record.dyn_cast<Expr *>(); + Expected<Expr *> ToConstraintExpr = import(ConstraintExpr); + if(!ToConstraintExpr) + return ToConstraintExpr.takeError(); + Satisfaction.Details.emplace_back(ToConstraintExpr.get()); + } + } + } + return Satisfaction; + } }; template <typename InContainerTy> @@ -1193,37 +1226,11 @@ Expected<concepts::Requirement*> ASTNodeImporter::import(concepts::Requirement* if(ToExpr.get()->isInstantiationDependent()) return new (Importer.getToContext()) concepts::NestedRequirement(ToExpr.get()); else { - ConstraintSatisfaction Satisfaction; - Satisfaction.IsSatisfied = FromSatisfaction.IsSatisfied; - Satisfaction.ContainsErrors = FromSatisfaction.ContainsErrors; - if (!Satisfaction.IsSatisfied) { - for (auto Record = FromSatisfaction.begin(); Record != FromSatisfaction.end(); ++Record) { - const Expr *ConstraintExpr = Record->first; - Expected<Expr *> ToConstraintExpr = import(ConstraintExpr); - if(!ToConstraintExpr) - return ToConstraintExpr.takeError(); - if(Record->second.is<Expr*>()) { - Expected<Expr *> ToSecondExpr = import(Record->second.get<Expr*>()); - if(!ToSecondExpr) - return ToSecondExpr.takeError(); - Satisfaction.Details.emplace_back(ToConstraintExpr.get(),ToSecondExpr.get()); - } else { - std::pair<SourceLocation, StringRef> *pair = Record->second.get< - std::pair<SourceLocation, StringRef> *>(); - Error Err = Error::success(); - - auto ToPairFirst = import(pair->first); - if(!ToPairFirst) - return ToPairFirst.takeError(); - StringRef ToPairSecond = ImportStringRef(pair->second); - Satisfaction.Details.emplace_back( - ToConstraintExpr.get(), new (Importer.getToContext()) - ConstraintSatisfaction::SubstitutionDiagnostic{ - ToPairFirst.get(), ToPairSecond}); - } - } + auto expected_satisfaction = FillConstraintSatisfaction(FromSatisfaction); + if (!expected_satisfaction) { + return expected_satisfaction.takeError(); } - return new (Importer.getToContext()) concepts::NestedRequirement(Importer.getToContext(),ToExpr.get(),Satisfaction); + return new (Importer.getToContext()) concepts::NestedRequirement(Importer.getToContext(),ToExpr.get(), *expected_satisfaction); } } break; @@ -7576,38 +7583,13 @@ ExpectedStmt ASTNodeImporter::VisitConceptSpecializationExpr(ConceptSpecializati std::copy(FromString.begin(),FromString.end(),ToDiagMessage); return StringRef(ToDiagMessage,FromString.size()); }; - ConstraintSatisfaction Satisfaction; - Satisfaction.IsSatisfied = FromSatisfaction.IsSatisfied; - Satisfaction.ContainsErrors = FromSatisfaction.ContainsErrors; - if (!Satisfaction.IsSatisfied) { - for (auto Record = FromSatisfaction.begin(); Record != FromSatisfaction.end(); ++Record) { - const Expr *ConstraintExpr = Record->first; - Expected<Expr *> ToConstraintExpr = import(ConstraintExpr); - if(!ToConstraintExpr) - return ToConstraintExpr.takeError(); - if(Record->second.is<Expr*>()) { - Expected<Expr *> ToSecondExpr = import(Record->second.get<Expr*>()); - if(!ToSecondExpr) - return ToSecondExpr.takeError(); - Satisfaction.Details.emplace_back(ToConstraintExpr.get(),ToSecondExpr.get()); - } else { - std::pair<SourceLocation, StringRef> *pair = Record->second.get< - std::pair<SourceLocation, StringRef> *>(); - Error Err = Error::success(); - - auto ToPairFirst = import(pair->first); - if(!ToPairFirst) - return ToPairFirst.takeError(); - StringRef ToPairSecond = ImportStringRef(pair->second); - Satisfaction.Details.emplace_back( - ToConstraintExpr.get(), new(Importer.getToContext()) ConstraintSatisfaction::SubstitutionDiagnostic{ - ToPairFirst.get(), ToPairSecond}); - } - } + auto expected_satisfaction = FillConstraintSatisfaction(FromSatisfaction); + if (!expected_satisfaction) { + return expected_satisfaction.takeError(); } return ConceptSpecializationExpr::Create( Importer.getToContext(), CL, - const_cast<ImplicitConceptSpecializationDecl *>(CSD), &Satisfaction); + const_cast<ImplicitConceptSpecializationDecl *>(CSD), &*expected_satisfaction); } ExpectedDecl ASTNodeImporter::VisitConceptDecl(ConceptDecl* D) { >From 91080a74e71bb6b07eacf56ca0a4026944d83cc7 Mon Sep 17 00:00:00 2001 From: Konstantin Ganenko <ganenk...@yandex-team.ru> Date: Thu, 15 May 2025 15:31:32 +0300 Subject: [PATCH 03/18] Fix non working code: - unchecked errors - changes Decls were not mapped with helper GetImportedOrCreateDecl - SmallVectors were non initialized --- clang/lib/AST/ASTImporter.cpp | 83 +++++++++++++++++++---------------- 1 file changed, 44 insertions(+), 39 deletions(-) diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index f75326079d0f9..eec2edfff8d3b 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -754,8 +754,6 @@ namespace clang { using SubstitutionDiagnostic = std::pair<SourceLocation, StringRef>; for (auto &Record : from) { if (auto *SubstDiag = Record.dyn_cast<SubstitutionDiagnostic *>()) { - Error Err = Error::success(); - auto ToPairFirst = import(SubstDiag->first); if(!ToPairFirst) return ToPairFirst.takeError(); @@ -1112,6 +1110,9 @@ Expected<concepts::Requirement*> ASTNodeImporter::import(concepts::Requirement* auto ImportSubstitutionDiagnos = [this, &ImportStringRef] (concepts::Requirement::SubstitutionDiagnostic* FromDiagnos, Error& Err)->concepts::Requirement::SubstitutionDiagnostic* { + if (Err) { + return nullptr; + } const auto& ToEntity = ImportStringRef(FromDiagnos->SubstitutedEntity); Expected<SourceLocation> ToLoc = import(FromDiagnos->DiagLoc); if(!ToLoc) { @@ -1216,7 +1217,7 @@ Expected<concepts::Requirement*> ASTNodeImporter::import(concepts::Requirement* const auto& FromSatisfaction = From->getConstraintSatisfaction(); if(From->hasInvalidConstraint()) { const auto& ToConstraintEntity = ImportStringRef(From->getInvalidConstraintEntity()); - auto ToSatisfaction = ASTConstraintSatisfaction::Rebuild(Importer.getToContext(),FromSatisfaction); + auto* ToSatisfaction = ASTConstraintSatisfaction::Rebuild(Importer.getToContext(),FromSatisfaction); return new (Importer.getToContext()) concepts::NestedRequirement(ToConstraintEntity,ToSatisfaction); } else { Expected<Expr *> ToExpr = import(From->getConstraintExpr()); @@ -7545,11 +7546,11 @@ ExpectedStmt ASTNodeImporter::VisitRequiresExpr(RequiresExpr* E) { auto LParenLoc = importChecked(Err,E->getLParenLoc()); if(Err) return std::move(Err); - SmallVector<ParmVarDecl*, 4> LocalParameters; - if (Error Err = ImportArrayChecked(E->getLocalParameters(),LocalParameters.begin())) + SmallVector<ParmVarDecl*, 4> LocalParameters(E->getLocalParameters().size()); + if (Error Err = ImportArrayChecked(E->getLocalParameters(), LocalParameters.begin())) return std::move(Err); - SmallVector<concepts::Requirement*, 4> Requirements; - if (Error Err = ImportArrayChecked(E->getRequirements(),Requirements.begin())) + 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); @@ -7557,32 +7558,31 @@ ExpectedStmt ASTNodeImporter::VisitRequiresExpr(RequiresExpr* E) { ExpectedDecl ASTNodeImporter::VisitRequiresExprBodyDecl(RequiresExprBodyDecl* D) { DeclContext *DC, *LexicalDC; - Error Err = Error::success(); - Err = ImportDeclContext(D, DC, LexicalDC); - auto RequiresLoc = importChecked(Err,D->getLocation()); - return RequiresExprBodyDecl::Create(Importer.getToContext(),DC,RequiresLoc); + 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; } ExpectedStmt ASTNodeImporter::VisitConceptSpecializationExpr(ConceptSpecializationExpr* E) { Error Err = Error::success(); - auto CL = importChecked(Err,E->getConceptReference()); auto CSD = importChecked(Err,E->getSpecializationDecl()); - // auto Satisfaction = importChecked(Err,E->getSatisfaction()); if (Err) return std::move(Err); - // E->getDependence(); if(E->isValueDependent()) { return ConceptSpecializationExpr::Create( Importer.getToContext(), CL, const_cast<ImplicitConceptSpecializationDecl *>(CSD), nullptr); } const auto& FromSatisfaction = E->getSatisfaction(); - auto ImportStringRef = [this](const StringRef& FromString) { - char* ToDiagMessage = new (Importer.getToContext()) char[FromString.size()]; - std::copy(FromString.begin(),FromString.end(),ToDiagMessage); - return StringRef(ToDiagMessage,FromString.size()); - }; auto expected_satisfaction = FillConstraintSatisfaction(FromSatisfaction); if (!expected_satisfaction) { return expected_satisfaction.takeError(); @@ -7594,34 +7594,39 @@ ExpectedStmt ASTNodeImporter::VisitConceptSpecializationExpr(ConceptSpecializati ExpectedDecl ASTNodeImporter::VisitConceptDecl(ConceptDecl* D) { // Import the context of this declaration. - DeclContext *DC, *LexicalDC; - Error Err = Error::success(); - Err = ImportDeclContext(D, DC, LexicalDC); - auto BeginLocOrErr = importChecked(Err, D->getBeginLoc()); + DeclContext *DC = nullptr; + DeclContext *LexicalDC = nullptr; + 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) + auto* ToTemplateParameters = importChecked(Err, D->getTemplateParameters()); + auto* ConstraintExpr = importChecked(Err, D->getConstraintExpr()); + if(Err) { return std::move(Err); - return ConceptDecl::Create( - Importer.getToContext(),DC, - LocationOrErr,NameDeclOrErr, - ToTemplateParameters,ConstraintExpr); + } + 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::VisitImplicitConceptSpecializationDecl(ImplicitConceptSpecializationDecl* D) { DeclContext *DC, *LexicalDC; - Error Err = Error::success(); - Err = ImportDeclContext(D, DC, LexicalDC); - auto ToSL = importChecked(Err,D->getLocation()); + Error Err = ImportDeclContext(D, DC, LexicalDC); + auto ToSL = importChecked(Err, D->getLocation()); if(Err) return std::move(Err); - SmallVector<TemplateArgument,2> ToArgs; - if(Error Err = ImportTemplateArguments(D->getTemplateArguments(),ToArgs)) + SmallVector<TemplateArgument,2> ToArgs(D->getTemplateArguments().size()); + if(Error Err = ImportTemplateArguments(D->getTemplateArguments(), ToArgs)) return std::move(Err); - - return ImplicitConceptSpecializationDecl::Create(Importer.getToContext(),DC,ToSL,ToArgs); + ImplicitConceptSpecializationDecl *To; + if (GetImportedOrCreateDecl(To, D, Importer.getToContext(), DC, ToSL, ToArgs)) + return To; + To->setLexicalDeclContext(LexicalDC); + LexicalDC->addDeclInternal(To); + return To; } ExpectedStmt ASTNodeImporter::VisitSourceLocExpr(SourceLocExpr *E) { @@ -7644,8 +7649,8 @@ ExpectedStmt ASTNodeImporter::VisitVAArgExpr(VAArgExpr *E) { Error Err = Error::success(); auto ToBuiltinLoc = importChecked(Err, E->getBuiltinLoc()); - auto ToSubExpr = importChecked(Err, E->getSubExpr()); - auto ToWrittenTypeInfo = importChecked(Err, E->getWrittenTypeInfo()); + auto* ToSubExpr = importChecked(Err, E->getSubExpr()); + auto* ToWrittenTypeInfo = importChecked(Err, E->getWrittenTypeInfo()); auto ToRParenLoc = importChecked(Err, E->getRParenLoc()); auto ToType = importChecked(Err, E->getType()); if (Err) >From e74b9c32361e4c2975a7b03865ed3c08048c04bd Mon Sep 17 00:00:00 2001 From: Konstantin Ganenko <ganenk...@yandex-team.ru> Date: Wed, 4 Jun 2025 16:08:00 +0300 Subject: [PATCH 04/18] Fix isDependent calculation in ReturnTypeRequirement ctor. --- clang/include/clang/AST/ExprConcepts.h | 1 + clang/lib/AST/ASTConcept.cpp | 4 ++++ clang/lib/AST/ASTImporter.cpp | 3 ++- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/clang/include/clang/AST/ExprConcepts.h b/clang/include/clang/AST/ExprConcepts.h index 8df5cdcaa9d75..7ab0c3e0b2769 100644 --- a/clang/include/clang/AST/ExprConcepts.h +++ b/clang/include/clang/AST/ExprConcepts.h @@ -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 { diff --git a/clang/lib/AST/ASTConcept.cpp b/clang/lib/AST/ASTConcept.cpp index c9cfec6bd64b5..91ab66f4639fc 100644 --- a/clang/lib/AST/ASTConcept.cpp +++ b/clang/lib/AST/ASTConcept.cpp @@ -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(), diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index eec2edfff8d3b..efd7f4f2ce7ea 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -1176,6 +1176,7 @@ Expected<concepts::Requirement*> ASTNodeImporter::import(concepts::Requirement* auto& FromTypeRequirement = From->getReturnTypeRequirement(); if(FromTypeRequirement.isTypeConstraint()) { + const bool IsDependent = FromTypeRequirement.isDependent(); auto ParamsOrErr = import(FromTypeRequirement.getTypeConstraintTemplateParameterList()); if (!ParamsOrErr) return ParamsOrErr.takeError(); @@ -1186,7 +1187,7 @@ Expected<concepts::Requirement*> ASTNodeImporter::import(concepts::Requirement* return ExpectSubstitutedConstraintExpr.takeError(); SubstitutedConstraintExpr = ExpectSubstitutedConstraintExpr.get(); } - Req.emplace(ParamsOrErr.get()); + Req.emplace(ParamsOrErr.get(), IsDependent); } else if(FromTypeRequirement.isSubstitutionFailure()) { Error Err = Error::success(); >From 5f4d8da7cfab56c12f8a1e5c1942eb757f91503a Mon Sep 17 00:00:00 2001 From: Konstantin Ganenko <ganenk...@yandex-team.ru> Date: Wed, 4 Jun 2025 16:11:16 +0300 Subject: [PATCH 05/18] Add newly imported declarations into imported cache --- clang/lib/AST/ASTImporter.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index efd7f4f2ce7ea..e57d00cc67fd7 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -7569,7 +7569,7 @@ ExpectedDecl ASTNodeImporter::VisitRequiresExprBodyDecl(RequiresExprBodyDecl* D) return To; To->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(To); - return To; + return Importer.MapImported(D, To); } ExpectedStmt ASTNodeImporter::VisitConceptSpecializationExpr(ConceptSpecializationExpr* E) { @@ -7610,7 +7610,7 @@ ExpectedDecl ASTNodeImporter::VisitConceptDecl(ConceptDecl* D) { return To; To->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(To); - return To; + return Importer.MapImported(D, To); } ExpectedDecl ASTNodeImporter::VisitImplicitConceptSpecializationDecl(ImplicitConceptSpecializationDecl* D) { @@ -7627,7 +7627,7 @@ ExpectedDecl ASTNodeImporter::VisitImplicitConceptSpecializationDecl(ImplicitCon return To; To->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(To); - return To; + return Importer.MapImported(D, To); } ExpectedStmt ASTNodeImporter::VisitSourceLocExpr(SourceLocExpr *E) { >From a853cfd1bc472f1f1d779b10f448896e03aca183 Mon Sep 17 00:00:00 2001 From: Konstantin Ganenko <ganenk...@yandex-team.ru> Date: Mon, 9 Jun 2025 10:04:44 +0300 Subject: [PATCH 06/18] Add debug build folder to ignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index a84268a7f6863..1f4a07d4b9e50 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,7 @@ # Nested build directory /build* +/debug* #==============================================================================# # Explicit files to ignore (only matches one). >From 0fa55406474915260bb4b7a6ec33d104359d47fe Mon Sep 17 00:00:00 2001 From: Konstantin Ganenko <ganenk...@yandex-team.ru> Date: Mon, 9 Jun 2025 10:05:13 +0300 Subject: [PATCH 07/18] Revert "Add newly imported declarations into imported cache" This reverts commit 3380e263eb06287e8c36ca88c60b1c38ec1ad0ae. --- clang/lib/AST/ASTImporter.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index e57d00cc67fd7..efd7f4f2ce7ea 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -7569,7 +7569,7 @@ ExpectedDecl ASTNodeImporter::VisitRequiresExprBodyDecl(RequiresExprBodyDecl* D) return To; To->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(To); - return Importer.MapImported(D, To); + return To; } ExpectedStmt ASTNodeImporter::VisitConceptSpecializationExpr(ConceptSpecializationExpr* E) { @@ -7610,7 +7610,7 @@ ExpectedDecl ASTNodeImporter::VisitConceptDecl(ConceptDecl* D) { return To; To->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(To); - return Importer.MapImported(D, To); + return To; } ExpectedDecl ASTNodeImporter::VisitImplicitConceptSpecializationDecl(ImplicitConceptSpecializationDecl* D) { @@ -7627,7 +7627,7 @@ ExpectedDecl ASTNodeImporter::VisitImplicitConceptSpecializationDecl(ImplicitCon return To; To->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(To); - return Importer.MapImported(D, To); + return To; } ExpectedStmt ASTNodeImporter::VisitSourceLocExpr(SourceLocExpr *E) { >From 35289b2c88a682aba053ec8e64a6ba79f14286fd Mon Sep 17 00:00:00 2001 From: Konstantin Ganenko <ganenk...@yandex-team.ru> Date: Mon, 9 Jun 2025 11:40:08 +0300 Subject: [PATCH 08/18] Reformat changes. --- clang/lib/AST/ASTImporter.cpp | 434 +++++++++++++++++----------------- 1 file changed, 214 insertions(+), 220 deletions(-) diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index efd7f4f2ce7ea..42ad636d120a9 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -495,6 +495,16 @@ namespace clang { Expected<InheritedConstructor> ImportInheritedConstructor(const InheritedConstructor &From); + 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); @@ -740,38 +750,6 @@ namespace clang { // that type is declared inside the body of the function. // E.g. auto f() { struct X{}; return X(); } bool hasReturnTypeDeclaredInside(FunctionDecl *D); - - Expected<ConstraintSatisfaction> FillConstraintSatisfaction(const ASTConstraintSatisfaction& from) { - auto ImportStringRef = [this](const StringRef& FromString) { - char* ToDiagMessage = new (Importer.getToContext()) char[FromString.size()]; - std::copy(FromString.begin(),FromString.end(),ToDiagMessage); - return StringRef(ToDiagMessage,FromString.size()); - }; - ConstraintSatisfaction Satisfaction; - Satisfaction.IsSatisfied = from.IsSatisfied; - Satisfaction.ContainsErrors = from.ContainsErrors; - if (!Satisfaction.IsSatisfied) { - using SubstitutionDiagnostic = std::pair<SourceLocation, StringRef>; - for (auto &Record : from) { - if (auto *SubstDiag = Record.dyn_cast<SubstitutionDiagnostic *>()) { - auto ToPairFirst = import(SubstDiag->first); - if(!ToPairFirst) - return ToPairFirst.takeError(); - StringRef ToPairSecond = ImportStringRef(SubstDiag->second); - Satisfaction.Details.emplace_back(new (Importer.getToContext()) - ConstraintSatisfaction::SubstitutionDiagnostic{ - ToPairFirst.get(), ToPairSecond}); - } else { - const Expr *ConstraintExpr = Record.dyn_cast<Expr *>(); - Expected<Expr *> ToConstraintExpr = import(ConstraintExpr); - if(!ToConstraintExpr) - return ToConstraintExpr.takeError(); - Satisfaction.Details.emplace_back(ToConstraintExpr.get()); - } - } - } - return Satisfaction; - } }; template <typename InContainerTy> @@ -1076,6 +1054,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; @@ -1100,146 +1249,6 @@ Expected<LambdaCapture> ASTNodeImporter::import(const LambdaCapture &From) { EllipsisLoc); } -template<> -Expected<concepts::Requirement*> ASTNodeImporter::import(concepts::Requirement* FromRequire) { - auto ImportStringRef = [this](const StringRef& FromString) { - char* ToDiagMessage = new (Importer.getToContext()) char[FromString.size()]; - std::copy(FromString.begin(),FromString.end(),ToDiagMessage); - return StringRef(ToDiagMessage,FromString.size()); - }; - - auto ImportSubstitutionDiagnos = [this, &ImportStringRef] - (concepts::Requirement::SubstitutionDiagnostic* FromDiagnos, Error& Err)->concepts::Requirement::SubstitutionDiagnostic* { - if (Err) { - return nullptr; - } - const auto& ToEntity = ImportStringRef(FromDiagnos->SubstitutedEntity); - Expected<SourceLocation> ToLoc = import(FromDiagnos->DiagLoc); - if(!ToLoc) { - Err = ToLoc.takeError(); - return nullptr; - } - const auto& ToDiagMessage = ImportStringRef(FromDiagnos->DiagMessage); - return new (Importer.getToContext()) concepts::Requirement::SubstitutionDiagnostic{ - ToEntity, - ToLoc.get(), - ToDiagMessage}; - }; - switch (FromRequire->getKind()) { - case concepts::Requirement::RequirementKind::RK_Type: { - auto *From = cast<concepts::TypeRequirement>(FromRequire); - if(From->isSubstitutionFailure()) - { - // Should we return Error directly if TypeRequirement isSubstitutionFailure? - Error Err = Error::success(); - auto Diagnos = ImportSubstitutionDiagnos(From->getSubstitutionDiagnostic(),Err); - if (Err) - return std::move(Err); - return new (Importer.getToContext()) concepts::TypeRequirement(Diagnos); - } - else { - Expected<TypeSourceInfo *> ToType = import(From->getType()); - if(!ToType) - return ToType.takeError(); - return new (Importer.getToContext()) concepts::TypeRequirement(ToType.get()); - } - break; - } - case concepts::Requirement::RequirementKind::RK_Compound: - case concepts::Requirement::RequirementKind::RK_Simple: { - const auto *From = cast<concepts::ExprRequirement>(FromRequire); - - auto Status = From->getSatisfactionStatus(); - llvm::PointerUnion<concepts::Requirement::SubstitutionDiagnostic *, Expr *> E; - if (Status == concepts::ExprRequirement::SS_ExprSubstitutionFailure) { - Error Err = Error::success(); - E = ImportSubstitutionDiagnos(From->getExprSubstitutionDiagnostic(),Err); - if (Err) - return std::move(Err); - } else { - auto ExpectE = import(From->getExpr()); - if (!ExpectE) - return ExpectE.takeError(); - E = ExpectE.get(); - } - - std::optional<concepts::ExprRequirement::ReturnTypeRequirement> Req; - ConceptSpecializationExpr *SubstitutedConstraintExpr = nullptr; - SourceLocation NoexceptLoc; - bool IsRKSimple = FromRequire->getKind() == concepts::Requirement::RK_Simple; - if (IsRKSimple) { - Req.emplace(); - } else { - auto NoexceptLoc = import(From->getNoexceptLoc()); - if(!NoexceptLoc) - return NoexceptLoc.takeError(); - auto& FromTypeRequirement = From->getReturnTypeRequirement(); - - if(FromTypeRequirement.isTypeConstraint()) { - const bool IsDependent = FromTypeRequirement.isDependent(); - auto ParamsOrErr = import(FromTypeRequirement.getTypeConstraintTemplateParameterList()); - if (!ParamsOrErr) - return ParamsOrErr.takeError(); - if (Status >= - concepts::ExprRequirement::SS_ConstraintsNotSatisfied) { - auto ExpectSubstitutedConstraintExpr = import(From->getReturnTypeRequirementSubstitutedConstraintExpr()); - if (!ExpectSubstitutedConstraintExpr) - return ExpectSubstitutedConstraintExpr.takeError(); - SubstitutedConstraintExpr = ExpectSubstitutedConstraintExpr.get(); - } - Req.emplace(ParamsOrErr.get(), IsDependent); - } - else if(FromTypeRequirement.isSubstitutionFailure()) { - Error Err = Error::success(); - concepts::Requirement::SubstitutionDiagnostic *ToDiagnos = - ImportSubstitutionDiagnos( - FromTypeRequirement.getSubstitutionDiagnostic(), Err); - if (Err) - return std::move(Err); - Req.emplace(ToDiagnos); - } - else { - Req.emplace(); - } - } - if (Expr *Ex = E.dyn_cast<Expr *>()) - return new (Importer.getToContext()) concepts::ExprRequirement( - Ex, IsRKSimple, NoexceptLoc, - std::move(*Req), Status, SubstitutedConstraintExpr); - else - return new (Importer.getToContext()) concepts::ExprRequirement( - E.get<concepts::Requirement::SubstitutionDiagnostic *>(), - IsRKSimple, NoexceptLoc, - std::move(*Req)); - break; - } - case concepts::Requirement::RequirementKind::RK_Nested: { - auto *From = cast<concepts::NestedRequirement>(FromRequire); - const auto& FromSatisfaction = From->getConstraintSatisfaction(); - if(From->hasInvalidConstraint()) { - const auto& ToConstraintEntity = ImportStringRef(From->getInvalidConstraintEntity()); - auto* ToSatisfaction = ASTConstraintSatisfaction::Rebuild(Importer.getToContext(),FromSatisfaction); - return new (Importer.getToContext()) concepts::NestedRequirement(ToConstraintEntity,ToSatisfaction); - } else { - Expected<Expr *> ToExpr = import(From->getConstraintExpr()); - if(!ToExpr) - return ToExpr.takeError(); - // FromSatisfaction.IsSatisfied; - if(ToExpr.get()->isInstantiationDependent()) - return new (Importer.getToContext()) concepts::NestedRequirement(ToExpr.get()); - else { - auto expected_satisfaction = FillConstraintSatisfaction(FromSatisfaction); - if (!expected_satisfaction) { - return expected_satisfaction.takeError(); - } - return new (Importer.getToContext()) concepts::NestedRequirement(Importer.getToContext(),ToExpr.get(), *expected_satisfaction); - } - } - break; - } - } -} - template <typename T> bool ASTNodeImporter::hasSameVisibilityContextAndLinkage(T *Found, T *From) { if (Found->getLinkageInternal() != From->getLinkageInternal()) @@ -7538,38 +7547,33 @@ ExpectedStmt ASTNodeImporter::VisitExpr(Expr *E) { ExpectedStmt ASTNodeImporter::VisitRequiresExpr(RequiresExpr* E) { Error Err = Error::success(); - // auto ToType = importChecked(Err, E->getType()); - auto RequiresKWLoc = importChecked(Err,E->getRequiresKWLoc()); - auto RParenLoc = importChecked(Err,E->getRParenLoc()); - auto RBraceLoc = importChecked(Err,E->getRBraceLoc()); + 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) + 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()); + 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); + return RequiresExpr::Create(Importer.getToContext(), RequiresKWLoc, Body, + LParenLoc, LocalParameters, RParenLoc, + Requirements, RBraceLoc); } ExpectedDecl ASTNodeImporter::VisitRequiresExprBodyDecl(RequiresExprBodyDecl* D) { DeclContext *DC, *LexicalDC; Error Err = ImportDeclContext(D, DC, LexicalDC); auto RequiresLoc = importChecked(Err, D->getLocation()); - if (Err) { + 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; + return RequiresExprBodyDecl::Create(Importer.getToContext(), DC, RequiresLoc); } ExpectedStmt ASTNodeImporter::VisitConceptSpecializationExpr(ConceptSpecializationExpr* E) { @@ -7578,56 +7582,46 @@ ExpectedStmt ASTNodeImporter::VisitConceptSpecializationExpr(ConceptSpecializati auto CSD = importChecked(Err,E->getSpecializationDecl()); if (Err) return std::move(Err); - if(E->isValueDependent()) { + if (E->isValueDependent()) return ConceptSpecializationExpr::Create( Importer.getToContext(), CL, const_cast<ImplicitConceptSpecializationDecl *>(CSD), nullptr); - } - const auto& FromSatisfaction = E->getSatisfaction(); - auto expected_satisfaction = FillConstraintSatisfaction(FromSatisfaction); - if (!expected_satisfaction) { - return expected_satisfaction.takeError(); - } + ConstraintSatisfaction Satisfaction; + if (Error Err = + ImportConstraintSatisfaction(E->getSatisfaction(), Satisfaction)) + return std::move(Err); return ConceptSpecializationExpr::Create( - Importer.getToContext(), CL, - const_cast<ImplicitConceptSpecializationDecl *>(CSD), &*expected_satisfaction); + Importer.getToContext(), CL, + const_cast<ImplicitConceptSpecializationDecl *>(CSD), &Satisfaction); } ExpectedDecl ASTNodeImporter::VisitConceptDecl(ConceptDecl* D) { - // Import the context of this declaration. - DeclContext *DC = nullptr; - DeclContext *LexicalDC = nullptr; + 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) { + 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; + + return ConceptDecl::Create(Importer.getToContext(), DC, LocationOrErr, + NameDeclOrErr, ToTemplateParameters, + ConstraintExpr); } ExpectedDecl ASTNodeImporter::VisitImplicitConceptSpecializationDecl(ImplicitConceptSpecializationDecl* D) { DeclContext *DC, *LexicalDC; Error Err = ImportDeclContext(D, DC, LexicalDC); auto ToSL = importChecked(Err, D->getLocation()); - if(Err) + if (Err) return std::move(Err); + SmallVector<TemplateArgument,2> ToArgs(D->getTemplateArguments().size()); - if(Error Err = ImportTemplateArguments(D->getTemplateArguments(), ToArgs)) + 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; + return ImplicitConceptSpecializationDecl::Create(Importer.getToContext(), DC, + ToSL, ToArgs); } ExpectedStmt ASTNodeImporter::VisitSourceLocExpr(SourceLocExpr *E) { >From bd123b8ff7f29bce7869f2b8a6f60a43abc897e8 Mon Sep 17 00:00:00 2001 From: Konstantin Ganenko <ganenk...@yandex-team.ru> Date: Mon, 9 Jun 2025 11:47:58 +0300 Subject: [PATCH 09/18] Code review --- clang/lib/AST/ASTImporter.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 42ad636d120a9..4c92dd07e6c73 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -7644,8 +7644,8 @@ ExpectedStmt ASTNodeImporter::VisitVAArgExpr(VAArgExpr *E) { Error Err = Error::success(); auto ToBuiltinLoc = importChecked(Err, E->getBuiltinLoc()); - auto* ToSubExpr = importChecked(Err, E->getSubExpr()); - auto* ToWrittenTypeInfo = importChecked(Err, E->getWrittenTypeInfo()); + auto ToSubExpr = importChecked(Err, E->getSubExpr()); + auto ToWrittenTypeInfo = importChecked(Err, E->getWrittenTypeInfo()); auto ToRParenLoc = importChecked(Err, E->getRParenLoc()); auto ToType = importChecked(Err, E->getType()); if (Err) @@ -10850,4 +10850,4 @@ bool ASTImporter::IsStructurallyEquivalent(QualType From, QualType To, getToContext().getLangOpts(), FromContext, ToContext, NonEquivalentDecls, getStructuralEquivalenceKind(*this), false, Complain); return Ctx.IsEquivalent(From, To); -} \ No newline at end of file +} >From e1ce401188a35ee00ec4bf2eb8e1e7156dbb063f Mon Sep 17 00:00:00 2001 From: Konstantin Ganenko <ganenk...@yandex-team.ru> Date: Mon, 9 Jun 2025 13:23:57 +0300 Subject: [PATCH 10/18] Appply lost changes in new visit.*decl. Always use GetImportedOrCreateDecl for these. --- clang/lib/AST/ASTImporter.cpp | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 4c92dd07e6c73..9aa1a067b419f 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -7573,7 +7573,13 @@ ExpectedDecl ASTNodeImporter::VisitRequiresExprBodyDecl(RequiresExprBodyDecl* D) auto RequiresLoc = importChecked(Err, D->getLocation()); if (Err) return std::move(Err); - return RequiresExprBodyDecl::Create(Importer.getToContext(), DC, RequiresLoc); + + RequiresExprBodyDecl *To; + if (GetImportedOrCreateDecl(To, D, Importer.getToContext(), DC, RequiresLoc)) + return To; + To->setLexicalDeclContext(LexicalDC); + LexicalDC->addDeclInternal(To); + return To; } ExpectedStmt ASTNodeImporter::VisitConceptSpecializationExpr(ConceptSpecializationExpr* E) { @@ -7605,9 +7611,15 @@ ExpectedDecl ASTNodeImporter::VisitConceptDecl(ConceptDecl* D) { if (Err) return std::move(Err); - return ConceptDecl::Create(Importer.getToContext(), DC, LocationOrErr, + ConceptDecl *To; + if (GetImportedOrCreateDecl(To, D, + Importer.getToContext(), DC, LocationOrErr, NameDeclOrErr, ToTemplateParameters, - ConstraintExpr); + ConstraintExpr)) + return To; + To->setLexicalDeclContext(LexicalDC); + LexicalDC->addDeclInternal(To); + return To; } ExpectedDecl ASTNodeImporter::VisitImplicitConceptSpecializationDecl(ImplicitConceptSpecializationDecl* D) { @@ -7620,8 +7632,13 @@ ExpectedDecl ASTNodeImporter::VisitImplicitConceptSpecializationDecl(ImplicitCon SmallVector<TemplateArgument,2> ToArgs(D->getTemplateArguments().size()); if (Error Err = ImportTemplateArguments(D->getTemplateArguments(), ToArgs)) return std::move(Err); - return ImplicitConceptSpecializationDecl::Create(Importer.getToContext(), DC, - ToSL, ToArgs); + + ImplicitConceptSpecializationDecl *To; + if (GetImportedOrCreateDecl(To, D, Importer.getToContext(), DC, ToSL, ToArgs)) + return To; + To->setLexicalDeclContext(LexicalDC); + LexicalDC->addDeclInternal(To); + return To; } ExpectedStmt ASTNodeImporter::VisitSourceLocExpr(SourceLocExpr *E) { >From adcf915f07679efdc374fe1bb039c5490de11dc9 Mon Sep 17 00:00:00 2001 From: Konstantin Ganenko <ganenk...@yandex-team.ru> Date: Wed, 11 Jun 2025 13:07:03 +0300 Subject: [PATCH 11/18] Add tests for ASTImporter on newly added functions Test cover all code path including new visit and import functions for concept and requirement declarations and expressions. --- clang/include/clang/ASTMatchers/ASTMatchers.h | 21 ++++ clang/lib/ASTMatchers/ASTMatchersInternal.cpp | 4 + clang/unittests/AST/ASTImporterTest.cpp | 97 +++++++++++++++++++ 3 files changed, 122 insertions(+) diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h index e4d605d165324..e2700fd8dbaa0 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchers.h +++ b/clang/include/clang/ASTMatchers/ASTMatchers.h @@ -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" @@ -1363,6 +1364,26 @@ extern const internal::VariadicDynCastAllOfMatcher<Decl, CXXDeductionGuideDecl> extern const internal::VariadicDynCastAllOfMatcher<Decl, ConceptDecl> conceptDecl; +/// Matches concept requirement. +/// +/// Example matches requirement expression +/// \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 equirement body declaration +/// \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 diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp index 9cc50a656d37f..80dc888811657 100644 --- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp +++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp @@ -15,6 +15,7 @@ #include "clang/AST/ASTTypeTraits.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclTemplate.h" +#include "clang/AST/ExprConcepts.h" #include "clang/AST/ParentMapContext.h" #include "clang/AST/PrettyPrinter.h" #include "clang/ASTMatchers/ASTMatchers.h" @@ -826,6 +827,9 @@ const internal::VariadicDynCastAllOfMatcher<Decl, CXXMethodDecl> cxxMethodDecl; const internal::VariadicDynCastAllOfMatcher<Decl, CXXConversionDecl> cxxConversionDecl; const internal::VariadicDynCastAllOfMatcher<Decl, ConceptDecl> conceptDecl; +const internal::VariadicDynCastAllOfMatcher<Expr, RequiresExpr> requiresExpr; +const internal::VariadicDynCastAllOfMatcher<Decl, RequiresExprBodyDecl> + requiresExprBodyDecl; const internal::VariadicDynCastAllOfMatcher<Decl, VarDecl> varDecl; const internal::VariadicDynCastAllOfMatcher<Decl, FieldDecl> fieldDecl; const internal::VariadicDynCastAllOfMatcher<Decl, IndirectFieldDecl> diff --git a/clang/unittests/AST/ASTImporterTest.cpp b/clang/unittests/AST/ASTImporterTest.cpp index 86c3bd686c031..c0fb642d817a0 100644 --- a/clang/unittests/AST/ASTImporterTest.cpp +++ b/clang/unittests/AST/ASTImporterTest.cpp @@ -10,6 +10,7 @@ // //===----------------------------------------------------------------------===// +#include "clang/AST/ExprConcepts.h" #include "clang/AST/RecordLayout.h" #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Testing/CommandLineArgs.h" @@ -3217,6 +3218,102 @@ TEST_P(ImportExpr, UnresolvedMemberExpr) { compoundStmt(has(callExpr(has(unresolvedMemberExpr()))))))))); } +TEST_P(ImportExpr, ConceptNoRequirement) { + MatchVerifier<Decl> Verifier; + const char *Code = R"( + template<typename T> + struct is_int { static const bool value = false; }; + template<> struct is_int<int> { static const bool value = true; }; + template<typename T> + concept declToImport = is_int<T>::value; + )"; + testImport(Code, Lang_CXX20, "", Lang_CXX20, Verifier, + conceptDecl(unless(has(requiresExpr())))); +} + +TEST_P(ImportExpr, ConceptSimpleRequirement) { + MatchVerifier<Decl> Verifier; + const char *Code = R"( + template <class T1, class T2> + concept declToImport = requires(T1 i, T2 j) { + i + j; + }; + )"; + testImport(Code, Lang_CXX20, "", Lang_CXX20, Verifier, + conceptDecl(has(requiresExpr(has(requiresExprBodyDecl()))))); +} + +TEST_P(ImportExpr, ConceptCompoundNonTypeRequirement) { + MatchVerifier<Decl> Verifier; + const char *Code = R"( + template <class T1, class T2> + concept declToImport = requires(T1 i, T2 j) { + {i + j}; + }; + )"; + testImport(Code, Lang_CXX20, "", Lang_CXX20, Verifier, + conceptDecl(has(requiresExpr(has(requiresExprBodyDecl()))))); +} + +TEST_P(ImportExpr, ConceptCompoundTypeRequirement) { + MatchVerifier<Decl> Verifier; + const char *Code = R"( + template<typename T> + struct is_int { static const bool value = false; }; + template<> struct is_int<int> { static const bool value = true; }; + + template<typename T> + concept type_is_int = is_int<T>::value; + + template<typename T> + concept declToImport = requires(T x) { + {x * 1} -> type_is_int; + }; + )"; + testImport(Code, Lang_CXX20, "", Lang_CXX20, Verifier, + conceptDecl(has(requiresExpr(has(requiresExprBodyDecl()))))); +} + +TEST_P(ImportExpr, ConceptTypeRequirement) { + MatchVerifier<Decl> Verifier; + const char *Code = R"( + template <class T> + concept declToImport = requires { + typename T::value; + }; + )"; + testImport(Code, Lang_CXX20, "", Lang_CXX20, Verifier, + conceptDecl(has(requiresExpr(has(requiresExprBodyDecl()))))); +} + +TEST_P(ImportExpr, ConceptNestedRequirement) { + MatchVerifier<Decl> Verifier; + const char *Code = R"( + template<typename T> + struct is_int { static const bool value = false; }; + template<> struct is_int<int> { static const bool value = true; }; + + template<typename T> + concept declToImport = requires(T x) { + requires is_int<T>::value; + }; + )"; + testImport(Code, Lang_CXX20, "", Lang_CXX20, Verifier, + conceptDecl(has(requiresExpr(has(requiresExprBodyDecl()))))); +} + +TEST_P(ImportExpr, ConceptNestedNonInstantiationDependentRequirement) { + MatchVerifier<Decl> Verifier; + const char *Code = R"( + template<typename T> + concept declToImport = requires { + requires sizeof(long) == sizeof(int); + }; + )"; + testImport(Code, Lang_CXX20, "", Lang_CXX20, Verifier, + conceptDecl(has(requiresExpr(has(requiresExprBodyDecl()))))); +} + class ImportImplicitMethods : public ASTImporterOptionSpecificTestBase { public: static constexpr auto DefaultCode = R"( >From 78625a78a90168db467e6277690ac95678d71ca3 Mon Sep 17 00:00:00 2001 From: Konstantin Ganenko <ganenk...@yandex-team.ru> Date: Mon, 16 Jun 2025 12:54:50 +0300 Subject: [PATCH 12/18] Fix runtime error on importing Substitution failure in type constraint. --- clang/lib/AST/ASTImporter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 9aa1a067b419f..b5a8e511cdc93 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -1151,7 +1151,7 @@ ASTNodeImporter::ImportExprRequirement(concepts::ExprRequirement *From) { Req.emplace(ParamsOrErr.get(), IsDependent); } else if (FromTypeRequirement.isSubstitutionFailure()) { auto DiagOrErr = import(FromTypeRequirement.getSubstitutionDiagnostic()); - if (DiagOrErr) + if (!DiagOrErr) return DiagOrErr.takeError(); Req.emplace(DiagOrErr.get()); } else { >From 421af991b2acc6bcb5387d92ad71e4dc0c579104 Mon Sep 17 00:00:00 2001 From: Konstantin Ganenko <ganenk...@yandex-team.ru> Date: Mon, 16 Jun 2025 13:21:33 +0300 Subject: [PATCH 13/18] Allow setting different errors for decl. We can come to setImportDeclError twice for same decl, like ClassTemplateDecl or ClassTemplateSpecializationDecl. I used to encounter this case with UnsupportedConstruct and NameConflict. --- clang/lib/AST/ASTImporter.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index b5a8e511cdc93..9912733650d71 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -10847,7 +10847,11 @@ void ASTImporter::setImportDeclError(Decl *From, ASTImportError Error) { (void)InsertRes; // Either we set the error for the first time, or we already had set one and // now we want to set the same error. - assert(InsertRes.second || InsertRes.first->second.Error == Error.Error); + // With concepts, there was a way to arrive at the same declaration with + // different errors for the ClassTemplateDecl and + // ClassTemplateSpecializationDecl types: UnsupportedConstruct + // and NameConflict. + // assert(InsertRes.second || InsertRes.first->second.Error == Error.Error); } bool ASTImporter::IsStructurallyEquivalent(QualType From, QualType To, >From f9f8143e511cab38b3fdb3d2e23cd7bf2ab67e23 Mon Sep 17 00:00:00 2001 From: Konstantin Ganenko <ganenk...@yandex-team.ru> Date: Mon, 16 Jun 2025 18:31:57 +0300 Subject: [PATCH 14/18] Revert "Allow setting different errors for decl." This reverts commit 0496b611f363f98a30fee3d4eb5eca74733e563b. --- clang/lib/AST/ASTImporter.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 9912733650d71..b5a8e511cdc93 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -10847,11 +10847,7 @@ void ASTImporter::setImportDeclError(Decl *From, ASTImportError Error) { (void)InsertRes; // Either we set the error for the first time, or we already had set one and // now we want to set the same error. - // With concepts, there was a way to arrive at the same declaration with - // different errors for the ClassTemplateDecl and - // ClassTemplateSpecializationDecl types: UnsupportedConstruct - // and NameConflict. - // assert(InsertRes.second || InsertRes.first->second.Error == Error.Error); + assert(InsertRes.second || InsertRes.first->second.Error == Error.Error); } bool ASTImporter::IsStructurallyEquivalent(QualType From, QualType To, >From fbba32c46704a967411da58527a75820f9b55a57 Mon Sep 17 00:00:00 2001 From: Konstantin Ganenko <ganenk...@yandex-team.ru> Date: Tue, 17 Jun 2025 10:49:20 +0300 Subject: [PATCH 15/18] Implement VisitSubstNonTypeTemplateParmPackExpr --- clang/lib/AST/ASTImporter.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index b5a8e511cdc93..2392a0bcab702 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -695,6 +695,8 @@ namespace clang { ExpectedStmt VisitCXXFoldExpr(CXXFoldExpr *E); ExpectedStmt VisitRequiresExpr(RequiresExpr* E); ExpectedStmt VisitConceptSpecializationExpr(ConceptSpecializationExpr* E); + ExpectedStmt + VisitSubstNonTypeTemplateParmPackExpr(SubstNonTypeTemplateParmPackExpr *E); // Helper for chaining together multiple imports. If an error is detected, // subsequent imports will return default constructed nodes, so that failure @@ -7641,6 +7643,21 @@ ExpectedDecl ASTNodeImporter::VisitImplicitConceptSpecializationDecl(ImplicitCon return To; } +ExpectedStmt ASTNodeImporter::VisitSubstNonTypeTemplateParmPackExpr( + SubstNonTypeTemplateParmPackExpr *E) { + Error Err = Error::success(); + auto ToType = importChecked(Err, E->getType()); + auto ToNameLoc = importChecked(Err, E->getParameterPackLocation()); + auto ToArgPack = importChecked(Err, E->getArgumentPack()); + auto ToAssociatedDecl = importChecked(Err, E->getAssociatedDecl()); + if (Err) + return std::move(Err); + + return new (Importer.getToContext()) SubstNonTypeTemplateParmPackExpr( + ToType, E->getValueKind(), ToNameLoc, ToArgPack, ToAssociatedDecl, + E->getIndex(), E->getFinal()); +} + ExpectedStmt ASTNodeImporter::VisitSourceLocExpr(SourceLocExpr *E) { Error Err = Error::success(); auto ToType = importChecked(Err, E->getType()); >From d627e8e00d9b82779f2a50e84999bdb6501227e0 Mon Sep 17 00:00:00 2001 From: Konstantin Ganenko <ganenk...@yandex-team.ru> Date: Tue, 17 Jun 2025 11:46:24 +0300 Subject: [PATCH 16/18] Implement VisitPseudoObjectExpr --- clang/lib/AST/ASTImporter.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 2392a0bcab702..7d8ed4ef7d636 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -697,6 +697,7 @@ namespace clang { ExpectedStmt VisitConceptSpecializationExpr(ConceptSpecializationExpr* E); ExpectedStmt VisitSubstNonTypeTemplateParmPackExpr(SubstNonTypeTemplateParmPackExpr *E); + ExpectedStmt VisitPseudoObjectExpr(PseudoObjectExpr *E); // Helper for chaining together multiple imports. If an error is detected, // subsequent imports will return default constructed nodes, so that failure @@ -7658,6 +7659,21 @@ ExpectedStmt ASTNodeImporter::VisitSubstNonTypeTemplateParmPackExpr( E->getIndex(), E->getFinal()); } +ExpectedStmt ASTNodeImporter::VisitPseudoObjectExpr(PseudoObjectExpr *E) { + SmallVector<Expr *, 4> ToSemantics(E->getNumSemanticExprs()); + if (Error Err = ImportContainerChecked(E->semantics(), ToSemantics)) + return std::move(Err); + Expr *ToSynt = nullptr; + if (const Expr *FromSynt = E->getSyntacticForm()) { + if (auto ToSyntOrErr = import(FromSynt)) + ToSynt = *ToSyntOrErr; + else + return ToSyntOrErr.takeError(); + } + return PseudoObjectExpr::Create(Importer.getToContext(), ToSynt, ToSemantics, + E->getResultExprIndex()); +} + ExpectedStmt ASTNodeImporter::VisitSourceLocExpr(SourceLocExpr *E) { Error Err = Error::success(); auto ToType = importChecked(Err, E->getType()); >From 5f667ecf65b0cc4d71940f0e221e6d540aa16c97 Mon Sep 17 00:00:00 2001 From: Konstantin Ganenko <ganenk...@yandex-team.ru> Date: Tue, 17 Jun 2025 14:11:47 +0300 Subject: [PATCH 17/18] Fix crash when lambda is null --- clang/lib/AST/ASTStructuralEquivalence.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp index 704de8156132c..fad8a9257f7ed 100644 --- a/clang/lib/AST/ASTStructuralEquivalence.cpp +++ b/clang/lib/AST/ASTStructuralEquivalence.cpp @@ -1609,6 +1609,12 @@ 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() && >From c424c59ab5821d69ebd7eed8cd8f84505ac7cfa6 Mon Sep 17 00:00:00 2001 From: Konstantin Ganenko <ganenk...@yandex-team.ru> Date: Tue, 17 Jun 2025 17:07:06 +0300 Subject: [PATCH 18/18] Implement VisitCXXParenListInitExpr --- clang/lib/AST/ASTImporter.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 7d8ed4ef7d636..9af43a8ad3661 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -698,6 +698,7 @@ namespace clang { ExpectedStmt VisitSubstNonTypeTemplateParmPackExpr(SubstNonTypeTemplateParmPackExpr *E); ExpectedStmt VisitPseudoObjectExpr(PseudoObjectExpr *E); + ExpectedStmt VisitCXXParenListInitExpr(CXXParenListInitExpr *E); // Helper for chaining together multiple imports. If an error is detected, // subsequent imports will return default constructed nodes, so that failure @@ -7674,6 +7675,24 @@ ExpectedStmt ASTNodeImporter::VisitPseudoObjectExpr(PseudoObjectExpr *E) { E->getResultExprIndex()); } +ExpectedStmt +ASTNodeImporter::VisitCXXParenListInitExpr(CXXParenListInitExpr *E) { + Error Err = Error::success(); + auto ToType = importChecked(Err, E->getType()); + auto ToInitLoc = importChecked(Err, E->getInitLoc()); + auto ToBeginLoc = importChecked(Err, E->getBeginLoc()); + auto ToEndLoc = importChecked(Err, E->getEndLoc()); + if (Err) + return std::move(Err); + + SmallVector<Expr *, 4> ToArgs(E->getInitExprs().size()); + if (Error Err = ImportContainerChecked(E->getInitExprs(), ToArgs)) + return std::move(Err); + return CXXParenListInitExpr::Create(Importer.getToContext(), ToArgs, ToType, + E->getUserSpecifiedInitExprs().size(), + ToInitLoc, ToBeginLoc, ToEndLoc); +} + ExpectedStmt ASTNodeImporter::VisitSourceLocExpr(SourceLocExpr *E) { Error Err = Error::success(); auto ToType = importChecked(Err, E->getType()); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits