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 <fd...@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); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits