[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