Author: ganenkokb-yandex Date: 2025-07-09T21:12:31+03:00 New Revision: a57aaedc35a39bd1f573929d5c2cb56fd1cccab4
URL: https://github.com/llvm/llvm-project/commit/a57aaedc35a39bd1f573929d5c2cb56fd1cccab4 DIFF: https://github.com/llvm/llvm-project/commit/a57aaedc35a39bd1f573929d5c2cb56fd1cccab4.diff LOG: Ast importer visitors (#138838) I've rebased commit from [Evianaive](https://github.com/Evianaive/llvm-project/commits?author=Evianaive) and compiled it. I hope it will speed up fix for #129393. --------- Co-authored-by: Evianaive <153540...@qq.com> Added: Modified: clang/include/clang/AST/ExprConcepts.h clang/include/clang/ASTMatchers/ASTMatchers.h clang/lib/AST/ASTConcept.cpp clang/lib/AST/ASTImporter.cpp clang/lib/AST/ASTStructuralEquivalence.cpp clang/lib/ASTMatchers/ASTMatchersInternal.cpp clang/unittests/AST/ASTImporterTest.cpp Removed: ################################################################################ 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/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h index bae004896c11f..ce5d529e813fd 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 '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 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 90d309e49b264..4d3bd985739fb 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -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); @@ -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); @@ -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 @@ -1038,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; @@ -6833,6 +7020,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 //---------------------------------------------------------------------------- @@ -9052,6 +9295,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(); diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp index 704de8156132c..3aa6b37844103 100644 --- a/clang/lib/AST/ASTStructuralEquivalence.cpp +++ b/clang/lib/AST/ASTStructuralEquivalence.cpp @@ -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() && 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"( _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits