[clang] [clang][ASTImporter] Import C++20 concepts related nodes (PR #104731)
Ding Fei via cfe-commits
cfe-commits at lists.llvm.org
Sun Aug 18 18:49:44 PDT 2024
https://github.com/danix800 created https://github.com/llvm/llvm-project/pull/104731
Related nodes including:
- ConceptDecl
- RequiresExprBodyDecl
- ImplicitConceptSpecializationDecl
- RequiresExpr
- ConceptSpecializationExpr
- concepts::Requirement
- concepts::ExprRequirement
- concepts::NestedRequirement
- concepts::TypeRequirement
- concepts::Requirement::ReturnTypeRequirement
- concepts::Requirement::SubstitutionDiagnostic
>From 0725f4da2355dbaecae950a2c8bbb75a8e5530b1 Mon Sep 17 00:00:00 2001
From: dingfei <fding at feysh.com>
Date: Mon, 19 Aug 2024 09:36:44 +0800
Subject: [PATCH] [clang][ASTImporter] Import C++20 concepts related nodes
Related nodes including:
- ConceptDecl
- RequiresExprBodyDecl
- ImplicitConceptSpecializationDecl
- RequiresExpr
- ConceptSpecializationExpr
- concepts::Requirement
- concepts::ExprRequirement
- concepts::NestedRequirement
- concepts::TypeRequirement
- concepts::Requirement::ReturnTypeRequirement
- concepts::Requirement::SubstitutionDiagnostic
---
clang/include/clang/AST/ExprConcepts.h | 32 ++-
clang/lib/AST/ASTImporter.cpp | 265 ++++++++++++++++++++++++
clang/lib/AST/ExprConcepts.cpp | 106 +++++++++-
clang/lib/Sema/SemaConcept.cpp | 58 ------
clang/unittests/AST/ASTImporterTest.cpp | 43 ++++
5 files changed, 437 insertions(+), 67 deletions(-)
diff --git a/clang/include/clang/AST/ExprConcepts.h b/clang/include/clang/AST/ExprConcepts.h
index 29913fd84c58b4..7c8972c0ced0bb 100644
--- a/clang/include/clang/AST/ExprConcepts.h
+++ b/clang/include/clang/AST/ExprConcepts.h
@@ -59,11 +59,21 @@ class ConceptSpecializationExpr final : public Expr {
ImplicitConceptSpecializationDecl *SpecDecl,
const ConstraintSatisfaction *Satisfaction);
+ ConceptSpecializationExpr(const ASTContext &C, ConceptReference *ConceptRef,
+ ImplicitConceptSpecializationDecl *SpecDecl,
+ ASTConstraintSatisfaction *Satisfaction);
+
ConceptSpecializationExpr(const ASTContext &C, ConceptReference *ConceptRef,
ImplicitConceptSpecializationDecl *SpecDecl,
const ConstraintSatisfaction *Satisfaction,
bool Dependent,
bool ContainsUnexpandedParameterPack);
+
+ ConceptSpecializationExpr(const ASTContext &C, ConceptReference *ConceptRef,
+ ImplicitConceptSpecializationDecl *SpecDecl,
+ ASTConstraintSatisfaction *Satisfaction,
+ bool Dependent,
+ bool ContainsUnexpandedParameterPack);
ConceptSpecializationExpr(EmptyShell Empty);
public:
@@ -72,13 +82,25 @@ class ConceptSpecializationExpr final : public Expr {
ImplicitConceptSpecializationDecl *SpecDecl,
const ConstraintSatisfaction *Satisfaction);
+ static ConceptSpecializationExpr *
+ Create(const ASTContext &C, ConceptReference *ConceptRef,
+ ImplicitConceptSpecializationDecl *SpecDecl,
+ ASTConstraintSatisfaction *Satisfaction);
+
static ConceptSpecializationExpr *
Create(const ASTContext &C, ConceptReference *ConceptRef,
ImplicitConceptSpecializationDecl *SpecDecl,
const ConstraintSatisfaction *Satisfaction, bool Dependent,
bool ContainsUnexpandedParameterPack);
+ static ConceptSpecializationExpr *
+ Create(const ASTContext &C, ConceptReference *ConceptRef,
+ ImplicitConceptSpecializationDecl *SpecDecl,
+ ASTConstraintSatisfaction *Satisfaction, bool Dependent,
+ bool ContainsUnexpandedParameterPack);
+
ArrayRef<TemplateArgument> getTemplateArguments() const {
+ assert(hasSpecializationDecl() && "Template Argument Decl not initialized");
return SpecDecl->getTemplateArguments();
}
@@ -113,8 +135,10 @@ class ConceptSpecializationExpr final : public Expr {
return ConceptRef->getConceptNameInfo();
}
+ bool hasSpecializationDecl() const { return SpecDecl != nullptr; }
+
const ImplicitConceptSpecializationDecl *getSpecializationDecl() const {
- assert(SpecDecl && "Template Argument Decl not initialized");
+ assert(hasSpecializationDecl() && "Template Argument Decl not initialized");
return SpecDecl;
}
@@ -445,6 +469,12 @@ class NestedRequirement : public Requirement {
"constructed with a ConstraintSatisfaction object");
}
+ NestedRequirement(Expr *Constraint,
+ const ASTConstraintSatisfaction *Satisfaction)
+ : Requirement(RK_Nested, Constraint->isInstantiationDependent(),
+ Constraint->containsUnexpandedParameterPack()),
+ Constraint(Constraint), Satisfaction(Satisfaction) {}
+
NestedRequirement(ASTContext &C, Expr *Constraint,
const ConstraintSatisfaction &Satisfaction)
: Requirement(RK_Nested, Constraint->isInstantiationDependent(),
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 3bc0a647ebf94f..0910f854e3e1c3 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -574,6 +574,10 @@ namespace clang {
ExpectedDecl VisitVarTemplateDecl(VarTemplateDecl *D);
ExpectedDecl VisitVarTemplateSpecializationDecl(VarTemplateSpecializationDecl *D);
ExpectedDecl VisitFunctionTemplateDecl(FunctionTemplateDecl *D);
+ ExpectedDecl VisitConceptDecl(ConceptDecl *D);
+ ExpectedDecl VisitRequiresExprBodyDecl(RequiresExprBodyDecl *D);
+ ExpectedDecl VisitImplicitConceptSpecializationDecl(
+ ImplicitConceptSpecializationDecl *D);
// Importing statements
ExpectedStmt VisitStmt(Stmt *S);
@@ -690,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
@@ -1072,6 +1078,136 @@ Expected<LambdaCapture> ASTNodeImporter::import(const LambdaCapture &From) {
EllipsisLoc);
}
+template <>
+Expected<concepts::Requirement::SubstitutionDiagnostic *>
+ASTNodeImporter::import(concepts::Requirement::SubstitutionDiagnostic *SD) {
+ ExpectedSLoc ToDiagLoc = Importer.Import(SD->DiagLoc);
+ if (!ToDiagLoc)
+ return ToDiagLoc.takeError();
+
+ auto &ToC = Importer.ToContext;
+ return new (ToC) concepts::Requirement::SubstitutionDiagnostic{
+ ToC.backupStr(SD->SubstitutedEntity), *ToDiagLoc,
+ ToC.backupStr(SD->DiagMessage)};
+}
+
+template <>
+Expected<concepts::ExprRequirement::ReturnTypeRequirement>
+ASTNodeImporter::import(
+ const concepts::ExprRequirement::ReturnTypeRequirement &R) {
+ if (R.isEmpty())
+ return concepts::ExprRequirement::ReturnTypeRequirement{};
+
+ if (R.isSubstitutionFailure()) {
+ auto ToSubstDiagOrErr = import(R.getSubstitutionDiagnostic());
+ if (!ToSubstDiagOrErr)
+ return ToSubstDiagOrErr.takeError();
+ return concepts::ExprRequirement::ReturnTypeRequirement(*ToSubstDiagOrErr);
+ }
+
+ auto TPLOrErr = import(R.getTypeConstraintTemplateParameterList());
+ if (!TPLOrErr)
+ return TPLOrErr.takeError();
+
+ return concepts::ExprRequirement::ReturnTypeRequirement(*TPLOrErr);
+}
+
+template <>
+Expected<concepts::ExprRequirement *>
+ASTNodeImporter::import(concepts::ExprRequirement *R) {
+ SourceLocation ToNoexceptLoc;
+ if (R->hasNoexceptRequirement()) {
+ auto ToNoexceptLocOrErr = Importer.Import(R->getNoexceptLoc());
+ if (!ToNoexceptLocOrErr)
+ return ToNoexceptLocOrErr.takeError();
+ ToNoexceptLoc = *ToNoexceptLocOrErr;
+ }
+
+ auto RetTypeRequirementOrErr = import(R->getReturnTypeRequirement());
+ if (!RetTypeRequirementOrErr)
+ return RetTypeRequirementOrErr.takeError();
+
+ auto RetTypeRequirement = *RetTypeRequirementOrErr;
+ auto &ToC = Importer.ToContext;
+ if (R->isExprSubstitutionFailure()) {
+ auto ToSubstDiagOrErr = import(R->getExprSubstitutionDiagnostic());
+ if (!ToSubstDiagOrErr)
+ return ToSubstDiagOrErr.takeError();
+
+ return new (ToC) concepts::ExprRequirement(
+ *ToSubstDiagOrErr, R->isSimple(), ToNoexceptLoc, RetTypeRequirement);
+ }
+
+ auto ToExprOrErr = Importer.Import(R->getExpr());
+ if (!ToExprOrErr)
+ return ToExprOrErr.takeError();
+
+ ConceptSpecializationExpr *ToCSE = nullptr;
+ if (R->getSatisfactionStatus() >=
+ concepts::ExprRequirement::SS_TypeRequirementSubstitutionFailure) {
+ auto ToCSEOrErr =
+ import(R->getReturnTypeRequirementSubstitutedConstraintExpr());
+ if (!ToCSEOrErr)
+ return ToCSEOrErr.takeError();
+ ToCSE = *ToCSEOrErr;
+ }
+
+ return new (ToC) concepts::ExprRequirement(*ToExprOrErr, R->isSimple(),
+ ToNoexceptLoc, RetTypeRequirement,
+ R->getSatisfactionStatus(), ToCSE);
+}
+
+template <>
+Expected<concepts::NestedRequirement *>
+ASTNodeImporter::import(concepts::NestedRequirement *R) {
+ auto &ToC = Importer.ToContext;
+ auto *ToASTSat =
+ ASTConstraintSatisfaction::Rebuild(ToC, R->getConstraintSatisfaction());
+
+ if (R->hasInvalidConstraint()) {
+ R->getInvalidConstraintEntity();
+ return new (ToC) concepts::NestedRequirement(
+ ToC.backupStr(R->getInvalidConstraintEntity()), ToASTSat);
+ }
+
+ Expr *FromExpr = R->getConstraintExpr();
+ auto ToExprOrErr = Importer.Import(FromExpr);
+ if (!ToExprOrErr)
+ return ToExprOrErr.takeError();
+
+ return new (ToC) concepts::NestedRequirement(
+ *ToExprOrErr,
+ ASTConstraintSatisfaction::Rebuild(ToC, R->getConstraintSatisfaction()));
+}
+
+template <>
+Expected<concepts::TypeRequirement *>
+ASTNodeImporter::import(concepts::TypeRequirement *R) {
+ auto &ToC = Importer.ToContext;
+ if (R->isSubstitutionFailure()) {
+ auto ToSubstDiagOrErr = import(R->getSubstitutionDiagnostic());
+ if (!ToSubstDiagOrErr)
+ return ToSubstDiagOrErr.takeError();
+ return new (ToC) concepts::TypeRequirement(*ToSubstDiagOrErr);
+ }
+
+ Expected<TypeSourceInfo *> ToTSI = Importer.Import(R->getType());
+ if (!ToTSI)
+ return ToTSI.takeError();
+ return new (ToC) concepts::TypeRequirement(*ToTSI);
+}
+
+template <>
+Expected<concepts::Requirement *>
+ASTNodeImporter::import(concepts::Requirement *R) {
+ auto Kind = R->getKind();
+ if (Kind == concepts::Requirement::RK_Type)
+ return import(cast<concepts::TypeRequirement>(R));
+ else if (Kind == concepts::Requirement::RK_Nested)
+ return import(cast<concepts::NestedRequirement>(R));
+ return import(cast<concepts::ExprRequirement>(R));
+}
+
template <typename T>
bool ASTNodeImporter::hasSameVisibilityContextAndLinkage(T *Found, T *From) {
if (Found->getLinkageInternal() != From->getLinkageInternal())
@@ -6788,6 +6924,81 @@ ASTNodeImporter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
return ToFunc;
}
+ExpectedDecl ASTNodeImporter::VisitConceptDecl(ConceptDecl *D) {
+ DeclContext *DC, *LexicalDC;
+ DeclarationName Name;
+ SourceLocation Loc;
+ NamedDecl *ToD;
+
+ if (Error Err = ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc))
+ return std::move(Err);
+
+ if (ToD)
+ return ToD;
+
+ auto ParamsOrErr = import(D->getTemplateParameters());
+ if (!ParamsOrErr)
+ return ParamsOrErr.takeError();
+ TemplateParameterList *Params = *ParamsOrErr;
+
+ ExpectedExpr ToConstraintClauseOrErr = import(D->getConstraintExpr());
+ if (!ToConstraintClauseOrErr)
+ return ToConstraintClauseOrErr.takeError();
+
+ Expr *ToConstraintClause = *ToConstraintClauseOrErr;
+
+ ConceptDecl *ToConcept = nullptr;
+ if (GetImportedOrCreateDecl(ToConcept, D, Importer.getToContext(), DC, Loc,
+ Name, Params, ToConstraintClause))
+ return ToConcept;
+
+ addDeclToContexts(D, ToConcept);
+
+ return ToConcept;
+}
+
+ExpectedDecl
+ASTNodeImporter::VisitRequiresExprBodyDecl(RequiresExprBodyDecl *D) {
+ DeclContext *DC, *LexicalDC;
+ if (Error Err = ImportDeclContext(D, DC, LexicalDC))
+ return std::move(Err);
+
+ ExpectedSLoc ToStartLocOrErr = import(D->getLocation());
+ if (!ToStartLocOrErr)
+ return ToStartLocOrErr.takeError();
+
+ SourceLocation ToStartLoc = *ToStartLocOrErr;
+
+ RequiresExprBodyDecl *ToD = nullptr;
+ if (GetImportedOrCreateDecl(ToD, D, Importer.getToContext(), DC, ToStartLoc))
+ return ToD;
+
+ return ToD;
+}
+
+ExpectedDecl ASTNodeImporter::VisitImplicitConceptSpecializationDecl(
+ ImplicitConceptSpecializationDecl *D) {
+ DeclContext *DC, *LexicalDC;
+ if (Error Err = ImportDeclContext(D, DC, LexicalDC))
+ return std::move(Err);
+
+ ExpectedSLoc ToLocOrErr = import(D->getLocation());
+ if (!ToLocOrErr)
+ return ToLocOrErr.takeError();
+
+ const auto &FromArgs = D->getTemplateArguments();
+ SmallVector<TemplateArgument, 4> ToArgs(FromArgs.size());
+ if (Error Err = ImportContainerChecked(FromArgs, ToArgs))
+ return std::move(Err);
+
+ ImplicitConceptSpecializationDecl *ToD = nullptr;
+ if (GetImportedOrCreateDecl(ToD, D, Importer.getToContext(), DC, *ToLocOrErr,
+ ToArgs))
+ return ToD;
+
+ return ToD;
+}
+
//----------------------------------------------------------------------------
// Import Statements
//----------------------------------------------------------------------------
@@ -9003,6 +9214,60 @@ ExpectedStmt ASTNodeImporter::VisitCXXFoldExpr(CXXFoldExpr *E) {
ToEllipsisLoc, ToRHS, ToRParenLoc, E->getNumExpansions());
}
+ExpectedStmt ASTNodeImporter::VisitRequiresExpr(RequiresExpr *E) {
+ auto ToBodyOrErr = import(E->getBody());
+ if (!ToBodyOrErr)
+ return ToBodyOrErr.takeError();
+
+ const auto &FromLocalParams = E->getLocalParameters();
+ SmallVector<ParmVarDecl *, 4> ToLocalParams(FromLocalParams.size());
+ if (Error Err = ImportContainerChecked(FromLocalParams, ToLocalParams))
+ return std::move(Err);
+
+ const auto &FromRequirements = E->getRequirements();
+ SmallVector<concepts::Requirement *, 4> ToRequirements(
+ FromRequirements.size());
+ if (Error Err = ImportContainerChecked(FromRequirements, ToRequirements))
+ return std::move(Err);
+
+ Error Err = Error::success();
+ SourceLocation RequiresKWLoc = importChecked(Err, E->getRequiresKWLoc());
+ SourceLocation ToLParenLoc = importChecked(Err, E->getLParenLoc());
+ SourceLocation ToRParenLoc = importChecked(Err, E->getRParenLoc());
+ SourceLocation ToRBrackeLoc = importChecked(Err, E->getRBraceLoc());
+
+ if (Err)
+ return std::move(Err);
+
+ return RequiresExpr::Create(Importer.getToContext(), RequiresKWLoc,
+ *ToBodyOrErr, ToLParenLoc, ToLocalParams,
+ ToRParenLoc, ToRequirements, ToRBrackeLoc);
+}
+
+ExpectedStmt
+ASTNodeImporter::VisitConceptSpecializationExpr(ConceptSpecializationExpr *E) {
+ auto ToConceptRefOrErr = import(E->getConceptReference());
+ if (!ToConceptRefOrErr)
+ return ToConceptRefOrErr.takeError();
+
+ ImplicitConceptSpecializationDecl *ToSpecDecl = nullptr;
+ if (E->hasSpecializationDecl()) {
+ auto ToSpecDeclOrErr = import(E->getSpecializationDecl());
+ if (!ToSpecDeclOrErr)
+ return ToSpecDeclOrErr.takeError();
+ ToSpecDecl = *ToSpecDeclOrErr;
+ }
+
+ auto &ToC = Importer.ToContext;
+ auto IsDependent = E->isValueDependent();
+ return ConceptSpecializationExpr::Create(
+ ToC, *ToConceptRefOrErr, ToSpecDecl,
+ !IsDependent
+ ? ASTConstraintSatisfaction::Rebuild(ToC, E->getSatisfaction())
+ : nullptr,
+ IsDependent, E->containsUnexpandedParameterPack());
+}
+
Error ASTNodeImporter::ImportOverriddenMethods(CXXMethodDecl *ToMethod,
CXXMethodDecl *FromMethod) {
Error ImportErrors = Error::success();
diff --git a/clang/lib/AST/ExprConcepts.cpp b/clang/lib/AST/ExprConcepts.cpp
index 0704630c0fc266..072a5a4b25d0fb 100644
--- a/clang/lib/AST/ExprConcepts.cpp
+++ b/clang/lib/AST/ExprConcepts.cpp
@@ -34,11 +34,17 @@ ConceptSpecializationExpr::ConceptSpecializationExpr(
const ASTContext &C, ConceptReference *Loc,
ImplicitConceptSpecializationDecl *SpecDecl,
const ConstraintSatisfaction *Satisfaction)
+ : ConceptSpecializationExpr(
+ C, Loc, SpecDecl,
+ Satisfaction ? ASTConstraintSatisfaction::Create(C, *Satisfaction)
+ : nullptr) {}
+
+ConceptSpecializationExpr::ConceptSpecializationExpr(
+ const ASTContext &C, ConceptReference *Loc,
+ ImplicitConceptSpecializationDecl *SpecDecl,
+ ASTConstraintSatisfaction *Satisfaction)
: Expr(ConceptSpecializationExprClass, C.BoolTy, VK_PRValue, OK_Ordinary),
- ConceptRef(Loc), SpecDecl(SpecDecl),
- Satisfaction(Satisfaction
- ? ASTConstraintSatisfaction::Create(C, *Satisfaction)
- : nullptr) {
+ ConceptRef(Loc), SpecDecl(SpecDecl), Satisfaction(Satisfaction) {
setDependence(computeDependence(this, /*ValueDependent=*/!Satisfaction));
// Currently guaranteed by the fact concepts can only be at namespace-scope.
@@ -63,16 +69,31 @@ ConceptSpecializationExpr::Create(const ASTContext &C, ConceptReference *Loc,
return new (C) ConceptSpecializationExpr(C, Loc, SpecDecl, Satisfaction);
}
+ConceptSpecializationExpr *
+ConceptSpecializationExpr::Create(const ASTContext &C, ConceptReference *Loc,
+ ImplicitConceptSpecializationDecl *SpecDecl,
+ ASTConstraintSatisfaction *Satisfaction) {
+ return new (C) ConceptSpecializationExpr(C, Loc, SpecDecl, Satisfaction);
+}
+
ConceptSpecializationExpr::ConceptSpecializationExpr(
const ASTContext &C, ConceptReference *Loc,
ImplicitConceptSpecializationDecl *SpecDecl,
const ConstraintSatisfaction *Satisfaction, bool Dependent,
bool ContainsUnexpandedParameterPack)
+ : ConceptSpecializationExpr(
+ C, Loc, SpecDecl,
+ Satisfaction ? ASTConstraintSatisfaction::Create(C, *Satisfaction)
+ : nullptr,
+ Dependent, ContainsUnexpandedParameterPack) {}
+
+ConceptSpecializationExpr::ConceptSpecializationExpr(
+ const ASTContext &C, ConceptReference *Loc,
+ ImplicitConceptSpecializationDecl *SpecDecl,
+ ASTConstraintSatisfaction *Satisfaction, bool Dependent,
+ bool ContainsUnexpandedParameterPack)
: Expr(ConceptSpecializationExprClass, C.BoolTy, VK_PRValue, OK_Ordinary),
- ConceptRef(Loc), SpecDecl(SpecDecl),
- Satisfaction(Satisfaction
- ? ASTConstraintSatisfaction::Create(C, *Satisfaction)
- : nullptr) {
+ ConceptRef(Loc), SpecDecl(SpecDecl), Satisfaction(Satisfaction) {
ExprDependence D = ExprDependence::None;
if (!Satisfaction)
D |= ExprDependence::Value;
@@ -94,6 +115,17 @@ ConceptSpecializationExpr::Create(const ASTContext &C, ConceptReference *Loc,
ContainsUnexpandedParameterPack);
}
+ConceptSpecializationExpr *
+ConceptSpecializationExpr::Create(const ASTContext &C, ConceptReference *Loc,
+ ImplicitConceptSpecializationDecl *SpecDecl,
+ ASTConstraintSatisfaction *Satisfaction,
+ bool Dependent,
+ bool ContainsUnexpandedParameterPack) {
+ return new (C)
+ ConceptSpecializationExpr(C, Loc, SpecDecl, Satisfaction, Dependent,
+ ContainsUnexpandedParameterPack);
+}
+
const TypeConstraint *
concepts::ExprRequirement::ReturnTypeRequirement::getTypeConstraint() const {
assert(isTypeConstraint());
@@ -193,3 +225,61 @@ RequiresExpr::Create(ASTContext &C, EmptyShell Empty,
alignof(RequiresExpr));
return new (Mem) RequiresExpr(C, Empty, NumLocalParameters, NumRequirements);
}
+
+concepts::ExprRequirement::ExprRequirement(
+ Expr *E, bool IsSimple, SourceLocation NoexceptLoc,
+ ReturnTypeRequirement Req, SatisfactionStatus Status,
+ ConceptSpecializationExpr *SubstitutedConstraintExpr)
+ : Requirement(IsSimple ? RK_Simple : RK_Compound, Status == SS_Dependent,
+ Status == SS_Dependent &&
+ (E->containsUnexpandedParameterPack() ||
+ Req.containsUnexpandedParameterPack()),
+ Status == SS_Satisfied),
+ Value(E), NoexceptLoc(NoexceptLoc), TypeReq(Req),
+ SubstitutedConstraintExpr(SubstitutedConstraintExpr), Status(Status) {
+ assert((!IsSimple || (Req.isEmpty() && NoexceptLoc.isInvalid())) &&
+ "Simple requirement must not have a return type requirement or a "
+ "noexcept specification");
+ assert((Status > SS_TypeRequirementSubstitutionFailure &&
+ Req.isTypeConstraint()) == (SubstitutedConstraintExpr != nullptr));
+}
+
+concepts::ExprRequirement::ExprRequirement(
+ SubstitutionDiagnostic *ExprSubstDiag, bool IsSimple,
+ SourceLocation NoexceptLoc, ReturnTypeRequirement Req)
+ : Requirement(IsSimple ? RK_Simple : RK_Compound, Req.isDependent(),
+ Req.containsUnexpandedParameterPack(), /*IsSatisfied=*/false),
+ Value(ExprSubstDiag), NoexceptLoc(NoexceptLoc), TypeReq(Req),
+ Status(SS_ExprSubstitutionFailure) {
+ assert((!IsSimple || (Req.isEmpty() && NoexceptLoc.isInvalid())) &&
+ "Simple requirement must not have a return type requirement or a "
+ "noexcept specification");
+}
+
+concepts::ExprRequirement::ReturnTypeRequirement::ReturnTypeRequirement(
+ TemplateParameterList *TPL)
+ : TypeConstraintInfo(TPL, false) {
+ assert(TPL->size() == 1);
+ const TypeConstraint *TC =
+ cast<TemplateTypeParmDecl>(TPL->getParam(0))->getTypeConstraint();
+ assert(TC &&
+ "TPL must have a template type parameter with a type constraint");
+ auto *Constraint =
+ cast<ConceptSpecializationExpr>(TC->getImmediatelyDeclaredConstraint());
+ bool Dependent =
+ Constraint->getTemplateArgsAsWritten() &&
+ TemplateSpecializationType::anyInstantiationDependentTemplateArguments(
+ Constraint->getTemplateArgsAsWritten()->arguments().drop_front(1));
+ TypeConstraintInfo.setInt(Dependent ? true : false);
+}
+
+concepts::TypeRequirement::TypeRequirement(TypeSourceInfo *T)
+ : Requirement(RK_Type, T->getType()->isInstantiationDependentType(),
+ T->getType()->containsUnexpandedParameterPack(),
+ // We reach this ctor with either dependent types (in which
+ // IsSatisfied doesn't matter) or with non-dependent type in
+ // which the existence of the type indicates satisfaction.
+ /*IsSatisfied=*/true),
+ Value(T),
+ Status(T->getType()->isInstantiationDependentType() ? SS_Dependent
+ : SS_Satisfied) {}
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index de24bbe7eb99ce..b7f70be58d5e3f 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -1869,61 +1869,3 @@ bool Sema::MaybeEmitAmbiguousAtomicConstraintsDiagnostic(NamedDecl *D1,
<< AmbiguousAtomic2->getSourceRange();
return true;
}
-
-concepts::ExprRequirement::ExprRequirement(
- Expr *E, bool IsSimple, SourceLocation NoexceptLoc,
- ReturnTypeRequirement Req, SatisfactionStatus Status,
- ConceptSpecializationExpr *SubstitutedConstraintExpr) :
- Requirement(IsSimple ? RK_Simple : RK_Compound, Status == SS_Dependent,
- Status == SS_Dependent &&
- (E->containsUnexpandedParameterPack() ||
- Req.containsUnexpandedParameterPack()),
- Status == SS_Satisfied), Value(E), NoexceptLoc(NoexceptLoc),
- TypeReq(Req), SubstitutedConstraintExpr(SubstitutedConstraintExpr),
- Status(Status) {
- assert((!IsSimple || (Req.isEmpty() && NoexceptLoc.isInvalid())) &&
- "Simple requirement must not have a return type requirement or a "
- "noexcept specification");
- assert((Status > SS_TypeRequirementSubstitutionFailure && Req.isTypeConstraint()) ==
- (SubstitutedConstraintExpr != nullptr));
-}
-
-concepts::ExprRequirement::ExprRequirement(
- SubstitutionDiagnostic *ExprSubstDiag, bool IsSimple,
- SourceLocation NoexceptLoc, ReturnTypeRequirement Req) :
- Requirement(IsSimple ? RK_Simple : RK_Compound, Req.isDependent(),
- Req.containsUnexpandedParameterPack(), /*IsSatisfied=*/false),
- Value(ExprSubstDiag), NoexceptLoc(NoexceptLoc), TypeReq(Req),
- Status(SS_ExprSubstitutionFailure) {
- assert((!IsSimple || (Req.isEmpty() && NoexceptLoc.isInvalid())) &&
- "Simple requirement must not have a return type requirement or a "
- "noexcept specification");
-}
-
-concepts::ExprRequirement::ReturnTypeRequirement::
-ReturnTypeRequirement(TemplateParameterList *TPL) :
- TypeConstraintInfo(TPL, false) {
- assert(TPL->size() == 1);
- const TypeConstraint *TC =
- cast<TemplateTypeParmDecl>(TPL->getParam(0))->getTypeConstraint();
- assert(TC &&
- "TPL must have a template type parameter with a type constraint");
- auto *Constraint =
- cast<ConceptSpecializationExpr>(TC->getImmediatelyDeclaredConstraint());
- bool Dependent =
- Constraint->getTemplateArgsAsWritten() &&
- TemplateSpecializationType::anyInstantiationDependentTemplateArguments(
- Constraint->getTemplateArgsAsWritten()->arguments().drop_front(1));
- TypeConstraintInfo.setInt(Dependent ? true : false);
-}
-
-concepts::TypeRequirement::TypeRequirement(TypeSourceInfo *T) :
- Requirement(RK_Type, T->getType()->isInstantiationDependentType(),
- T->getType()->containsUnexpandedParameterPack(),
- // We reach this ctor with either dependent types (in which
- // IsSatisfied doesn't matter) or with non-dependent type in
- // which the existence of the type indicates satisfaction.
- /*IsSatisfied=*/true),
- Value(T),
- Status(T->getType()->isInstantiationDependentType() ? SS_Dependent
- : SS_Satisfied) {}
diff --git a/clang/unittests/AST/ASTImporterTest.cpp b/clang/unittests/AST/ASTImporterTest.cpp
index cc87e83e86055f..06615dbcb2a9ae 100644
--- a/clang/unittests/AST/ASTImporterTest.cpp
+++ b/clang/unittests/AST/ASTImporterTest.cpp
@@ -7617,6 +7617,46 @@ TEST_P(ImportAutoFunctions, ReturnWithUnaryTransformType) {
EXPECT_TRUE(ToBar);
}
+struct ImportConcepts : ASTImporterOptionSpecificTestBase {
+ std::vector<std::string> getExtraArgs() const override {
+ return {"-fno-delayed-template-parsing"}; // deprecated after C++20
+ }
+};
+
+TEST_P(ImportConcepts, ImportConceptDecl) {
+ Decl *FromTU = getTuDecl(
+ R"(
+ template <typename T> concept c = requires(T t) { t; };
+
+ template<class T> constexpr bool is_meowable = true;
+ template<class T> constexpr bool is_cat = true;
+ template<class T> concept Meowable = is_meowable<T>;
+ template<class T> concept BadMeowableCat = is_meowable<T> && is_cat<T>;
+ template<class T> concept GoodMeowableCat = Meowable<T> && is_cat<T>;
+ )",
+ Lang_CXX20, "input0.cc");
+
+ ConceptDecl *FromC =
+ FirstDeclMatcher<ConceptDecl>().match(FromTU, conceptDecl(hasName("c")));
+ ConceptDecl *ToC = Import(FromC, Lang_CXX20);
+ EXPECT_TRUE(ToC);
+
+ ConceptDecl *FromMeowable = FirstDeclMatcher<ConceptDecl>().match(
+ FromTU, conceptDecl(hasName("Meowable")));
+ ConceptDecl *ToMeowable = Import(FromMeowable, Lang_CXX20);
+ EXPECT_TRUE(ToMeowable);
+
+ ConceptDecl *FromBadMeowableCat = FirstDeclMatcher<ConceptDecl>().match(
+ FromTU, conceptDecl(hasName("BadMeowableCat")));
+ ConceptDecl *ToBadMeowableCat = Import(FromBadMeowableCat, Lang_CXX20);
+ EXPECT_TRUE(ToBadMeowableCat);
+
+ ConceptDecl *FromGoodMeowableCat = FirstDeclMatcher<ConceptDecl>().match(
+ FromTU, conceptDecl(hasName("GoodMeowableCat")));
+ ConceptDecl *ToGoodMeowableCat = Import(FromGoodMeowableCat, Lang_CXX20);
+ EXPECT_TRUE(ToGoodMeowableCat);
+}
+
struct ImportSourceLocations : ASTImporterOptionSpecificTestBase {};
TEST_P(ImportSourceLocations, PreserveFileIDTreeStructure) {
@@ -10041,6 +10081,9 @@ INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ImportMatrixType,
INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ImportTemplateParmDeclDefaultValue,
DefaultTestValuesForRunOptions);
+INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ImportConcepts,
+ DefaultTestValuesForRunOptions);
+
// FIXME: Make ImportOpenCLPipe test work.
// INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ImportOpenCLPipe,
// DefaultTestValuesForRunOptions);
More information about the cfe-commits
mailing list