[clang] a57aaed - Ast importer visitors (#138838)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Jul 9 11:12:35 PDT 2025
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 <153540933 at 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"(
More information about the cfe-commits
mailing list