[clang] b876f6e - Reapply "GH58368: Correct concept checking in a lambda defined in concept""
Erich Keane via cfe-commits
cfe-commits at lists.llvm.org
Mon Oct 24 11:46:58 PDT 2022
Author: Erich Keane
Date: 2022-10-24T11:46:54-07:00
New Revision: b876f6e2f28779211a829d7d4e841fe68885ae20
URL: https://github.com/llvm/llvm-project/commit/b876f6e2f28779211a829d7d4e841fe68885ae20
DIFF: https://github.com/llvm/llvm-project/commit/b876f6e2f28779211a829d7d4e841fe68885ae20.diff
LOG: Reapply "GH58368: Correct concept checking in a lambda defined in concept""
This reverts commit 52930162870fee52d0d9c07c5d66e5dce32b08e8.
Now with updating the ASTBitcodes to show that this AST is incompatible
from the last.
Added:
Modified:
clang/include/clang/AST/ASTNodeTraverser.h
clang/include/clang/AST/DeclTemplate.h
clang/include/clang/AST/ExprConcepts.h
clang/include/clang/AST/RecursiveASTVisitor.h
clang/include/clang/Basic/DeclNodes.td
clang/include/clang/Serialization/ASTBitCodes.h
clang/lib/AST/ASTContext.cpp
clang/lib/AST/DeclBase.cpp
clang/lib/AST/DeclTemplate.cpp
clang/lib/AST/ExprConcepts.cpp
clang/lib/CodeGen/CGDecl.cpp
clang/lib/Sema/SemaConcept.cpp
clang/lib/Sema/SemaLambda.cpp
clang/lib/Sema/SemaTemplate.cpp
clang/lib/Sema/SemaTemplateInstantiate.cpp
clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
clang/lib/Sema/TreeTransform.h
clang/lib/Serialization/ASTCommon.cpp
clang/lib/Serialization/ASTReaderDecl.cpp
clang/lib/Serialization/ASTReaderStmt.cpp
clang/lib/Serialization/ASTWriterDecl.cpp
clang/lib/Serialization/ASTWriterStmt.cpp
clang/test/AST/ast-dump-concepts.cpp
clang/test/SemaTemplate/concepts-lambda.cpp
clang/tools/libclang/CIndex.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/AST/ASTNodeTraverser.h b/clang/include/clang/AST/ASTNodeTraverser.h
index 44dc52b419af5..6df3a83b6404a 100644
--- a/clang/include/clang/AST/ASTNodeTraverser.h
+++ b/clang/include/clang/AST/ASTNodeTraverser.h
@@ -623,7 +623,14 @@ class ASTNodeTraverser
Visit(D->getConstraintExpr());
}
+ void VisitImplicitConceptSpecializationDecl(
+ const ImplicitConceptSpecializationDecl *CSD) {
+ for (const TemplateArgument &Arg : CSD->getTemplateArguments())
+ Visit(Arg);
+ }
+
void VisitConceptSpecializationExpr(const ConceptSpecializationExpr *CSE) {
+ Visit(CSE->getSpecializationDecl());
if (CSE->hasExplicitTemplateArgs())
for (const auto &ArgLoc : CSE->getTemplateArgsAsWritten()->arguments())
dumpTemplateArgumentLoc(ArgLoc);
diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h
index ae10744383559..d1dfe73a51182 100644
--- a/clang/include/clang/AST/DeclTemplate.h
+++ b/clang/include/clang/AST/DeclTemplate.h
@@ -3259,7 +3259,7 @@ class VarTemplateDecl : public RedeclarableTemplateDecl {
static bool classofKind(Kind K) { return K == VarTemplate; }
};
-/// Declaration of a C++2a concept.
+/// Declaration of a C++20 concept.
class ConceptDecl : public TemplateDecl, public Mergeable<ConceptDecl> {
protected:
Expr *ConstraintExpr;
@@ -3304,6 +3304,40 @@ class ConceptDecl : public TemplateDecl, public Mergeable<ConceptDecl> {
friend class ASTDeclWriter;
};
+// An implementation detail of ConceptSpecialicationExpr that holds the template
+// arguments, so we can later use this to reconstitute the template arguments
+// during constraint checking.
+class ImplicitConceptSpecializationDecl final
+ : public Decl,
+ private llvm::TrailingObjects<ImplicitConceptSpecializationDecl,
+ TemplateArgument> {
+ unsigned NumTemplateArgs;
+
+ ImplicitConceptSpecializationDecl(DeclContext *DC, SourceLocation SL,
+ ArrayRef<TemplateArgument> ConvertedArgs);
+ ImplicitConceptSpecializationDecl(EmptyShell Empty, unsigned NumTemplateArgs);
+
+public:
+ static ImplicitConceptSpecializationDecl *
+ Create(const ASTContext &C, DeclContext *DC, SourceLocation SL,
+ ArrayRef<TemplateArgument> ConvertedArgs);
+ static ImplicitConceptSpecializationDecl *
+ CreateDeserialized(const ASTContext &C, unsigned ID,
+ unsigned NumTemplateArgs);
+
+ ArrayRef<TemplateArgument> getTemplateArguments() const {
+ return ArrayRef<TemplateArgument>(getTrailingObjects<TemplateArgument>(),
+ NumTemplateArgs);
+ }
+ void setTemplateArguments(ArrayRef<TemplateArgument> Converted);
+
+ static bool classofKind(Kind K) { return K == ImplicitConceptSpecialization; }
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
+
+ friend TrailingObjects;
+ friend class ASTDeclReader;
+};
+
/// A template parameter object.
///
/// Template parameter objects represent values of class type used as template
diff --git a/clang/include/clang/AST/ExprConcepts.h b/clang/include/clang/AST/ExprConcepts.h
index fd9cd31f3b90b..6dedeb5c8ddfa 100644
--- a/clang/include/clang/AST/ExprConcepts.h
+++ b/clang/include/clang/AST/ExprConcepts.h
@@ -37,18 +37,17 @@ class ASTStmtWriter;
///
/// According to C++2a [expr.prim.id]p3 an id-expression that denotes the
/// specialization of a concept results in a prvalue of type bool.
-class ConceptSpecializationExpr final : public Expr, public ConceptReference,
- private llvm::TrailingObjects<ConceptSpecializationExpr,
- TemplateArgument> {
+class ConceptSpecializationExpr final : public Expr, public ConceptReference {
+ friend class ASTReader;
friend class ASTStmtReader;
- friend TrailingObjects;
+
public:
using SubstitutionDiagnostic = std::pair<SourceLocation, std::string>;
protected:
- /// \brief The number of template arguments in the tail-allocated list of
- /// converted template arguments.
- unsigned NumTemplateArgs;
+ /// \brief The Implicit Concept Specialization Decl, which holds the template
+ /// arguments for this specialization.
+ ImplicitConceptSpecializationDecl *SpecDecl;
/// \brief Information about the satisfaction of the named concept with the
/// given arguments. If this expression is value dependent, this is to be
@@ -60,51 +59,46 @@ class ConceptSpecializationExpr final : public Expr, public ConceptReference,
DeclarationNameInfo ConceptNameInfo,
NamedDecl *FoundDecl, ConceptDecl *NamedConcept,
const ASTTemplateArgumentListInfo *ArgsAsWritten,
- ArrayRef<TemplateArgument> ConvertedArgs,
+ ImplicitConceptSpecializationDecl *SpecDecl,
const ConstraintSatisfaction *Satisfaction);
ConceptSpecializationExpr(const ASTContext &C, ConceptDecl *NamedConcept,
- ArrayRef<TemplateArgument> ConvertedArgs,
+ ImplicitConceptSpecializationDecl *SpecDecl,
const ConstraintSatisfaction *Satisfaction,
bool Dependent,
bool ContainsUnexpandedParameterPack);
-
- ConceptSpecializationExpr(EmptyShell Empty, unsigned NumTemplateArgs);
+ ConceptSpecializationExpr(EmptyShell Empty);
public:
-
static ConceptSpecializationExpr *
Create(const ASTContext &C, NestedNameSpecifierLoc NNS,
SourceLocation TemplateKWLoc, DeclarationNameInfo ConceptNameInfo,
NamedDecl *FoundDecl, ConceptDecl *NamedConcept,
const ASTTemplateArgumentListInfo *ArgsAsWritten,
- ArrayRef<TemplateArgument> ConvertedArgs,
+ ImplicitConceptSpecializationDecl *SpecDecl,
const ConstraintSatisfaction *Satisfaction);
static ConceptSpecializationExpr *
Create(const ASTContext &C, ConceptDecl *NamedConcept,
- ArrayRef<TemplateArgument> ConvertedArgs,
- const ConstraintSatisfaction *Satisfaction,
- bool Dependent,
+ ImplicitConceptSpecializationDecl *SpecDecl,
+ const ConstraintSatisfaction *Satisfaction, bool Dependent,
bool ContainsUnexpandedParameterPack);
- static ConceptSpecializationExpr *
- Create(ASTContext &C, EmptyShell Empty, unsigned NumTemplateArgs);
-
ArrayRef<TemplateArgument> getTemplateArguments() const {
- return ArrayRef<TemplateArgument>(getTrailingObjects<TemplateArgument>(),
- NumTemplateArgs);
+ return SpecDecl->getTemplateArguments();
}
- /// \brief Set new template arguments for this concept specialization.
- void setTemplateArguments(ArrayRef<TemplateArgument> Converted);
+ const ImplicitConceptSpecializationDecl *getSpecializationDecl() const {
+ assert(SpecDecl && "Template Argument Decl not initialized");
+ return SpecDecl;
+ }
/// \brief Whether or not the concept with the given arguments was satisfied
/// when the expression was created.
/// The expression must not be dependent.
bool isSatisfied() const {
- assert(!isValueDependent()
- && "isSatisfied called on a dependent ConceptSpecializationExpr");
+ assert(!isValueDependent() &&
+ "isSatisfied called on a dependent ConceptSpecializationExpr");
return Satisfaction->IsSatisfied;
}
@@ -112,8 +106,8 @@ class ConceptSpecializationExpr final : public Expr, public ConceptReference,
/// satisfaction of the named concept.
/// The expression must not be dependent.
const ASTConstraintSatisfaction &getSatisfaction() const {
- assert(!isValueDependent()
- && "getSatisfaction called on dependent ConceptSpecializationExpr");
+ assert(!isValueDependent() &&
+ "getSatisfaction called on dependent ConceptSpecializationExpr");
return *Satisfaction;
}
diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h
index b5c24e1a7661a..8c5412648bcd4 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -2304,6 +2304,11 @@ DEF_TRAVERSE_DECL(ParmVarDecl, {
DEF_TRAVERSE_DECL(RequiresExprBodyDecl, {})
+DEF_TRAVERSE_DECL(ImplicitConceptSpecializationDecl, {
+ TRY_TO(TraverseTemplateArguments(D->getTemplateArguments().data(),
+ D->getTemplateArguments().size()));
+})
+
#undef DEF_TRAVERSE_DECL
// ----------------- Stmt traversal -----------------
diff --git a/clang/include/clang/Basic/DeclNodes.td b/clang/include/clang/Basic/DeclNodes.td
index 386c0a1b3dbaa..c94c84ba25370 100644
--- a/clang/include/clang/Basic/DeclNodes.td
+++ b/clang/include/clang/Basic/DeclNodes.td
@@ -90,6 +90,7 @@ def Named : DeclNode<Decl, "named declarations", 1>;
def ObjCImplementation : DeclNode<ObjCImpl>;
def ObjCProperty : DeclNode<Named, "Objective-C properties">;
def ObjCCompatibleAlias : DeclNode<Named>;
+def ImplicitConceptSpecialization : DeclNode<Decl>;
def LinkageSpec : DeclNode<Decl>, DeclContext;
def Export : DeclNode<Decl>, DeclContext;
def ObjCPropertyImpl : DeclNode<Decl>;
diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h
index 3bbd2723be676..77d4a8a03c662 100644
--- a/clang/include/clang/Serialization/ASTBitCodes.h
+++ b/clang/include/clang/Serialization/ASTBitCodes.h
@@ -41,7 +41,7 @@ namespace serialization {
/// Version 4 of AST files also requires that the version control branch and
/// revision match exactly, since there is no backward compatibility of
/// AST files at this time.
-const unsigned VERSION_MAJOR = 22;
+const unsigned VERSION_MAJOR = 23;
/// AST file minor version number supported by this version of
/// Clang.
@@ -1514,7 +1514,10 @@ enum DeclCode {
/// A HLSLBufferDecl record.
DECL_HLSL_BUFFER,
- DECL_LAST = DECL_HLSL_BUFFER
+ /// An ImplicitConceptSpecializationDecl record.
+ DECL_IMPLICIT_CONCEPT_SPECIALIZATION,
+
+ DECL_LAST = DECL_IMPLICIT_CONCEPT_SPECIALIZATION
};
/// Record codes for each kind of statement or expression.
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 16852149792bb..08cbe2a9a5811 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -761,9 +761,13 @@ canonicalizeImmediatelyDeclaredConstraint(const ASTContext &C, Expr *IDC,
NewConverted.push_back(ConstrainedType);
llvm::append_range(NewConverted, OldConverted.drop_front(1));
}
+ auto *CSD = ImplicitConceptSpecializationDecl::Create(
+ C, CSE->getNamedConcept()->getDeclContext(),
+ CSE->getNamedConcept()->getLocation(), NewConverted);
+
Expr *NewIDC = ConceptSpecializationExpr::Create(
- C, CSE->getNamedConcept(), NewConverted, nullptr,
- CSE->isInstantiationDependent(), CSE->containsUnexpandedParameterPack());
+ C, CSE->getNamedConcept(), CSD, nullptr, CSE->isInstantiationDependent(),
+ CSE->containsUnexpandedParameterPack());
if (auto *OrigFold = dyn_cast<CXXFoldExpr>(IDC))
NewIDC = new (C) CXXFoldExpr(
diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp
index 72922ef977f92..5cb552372497d 100644
--- a/clang/lib/AST/DeclBase.cpp
+++ b/clang/lib/AST/DeclBase.cpp
@@ -874,6 +874,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case Empty:
case LifetimeExtendedTemporary:
case RequiresExprBody:
+ case ImplicitConceptSpecialization:
// Never looked up by name.
return 0;
}
diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp
index 9a2932c0bcbd8..deed47ec4a298 100644
--- a/clang/lib/AST/DeclTemplate.cpp
+++ b/clang/lib/AST/DeclTemplate.cpp
@@ -1052,6 +1052,44 @@ ConceptDecl *ConceptDecl::CreateDeserialized(ASTContext &C,
return Result;
}
+//===----------------------------------------------------------------------===//
+// ImplicitConceptSpecializationDecl Implementation
+//===----------------------------------------------------------------------===//
+ImplicitConceptSpecializationDecl::ImplicitConceptSpecializationDecl(
+ DeclContext *DC, SourceLocation SL,
+ ArrayRef<TemplateArgument> ConvertedArgs)
+ : Decl(ImplicitConceptSpecialization, DC, SL),
+ NumTemplateArgs(ConvertedArgs.size()) {
+ setTemplateArguments(ConvertedArgs);
+}
+
+ImplicitConceptSpecializationDecl::ImplicitConceptSpecializationDecl(
+ EmptyShell Empty, unsigned NumTemplateArgs)
+ : Decl(ImplicitConceptSpecialization, Empty),
+ NumTemplateArgs(NumTemplateArgs) {}
+
+ImplicitConceptSpecializationDecl *ImplicitConceptSpecializationDecl::Create(
+ const ASTContext &C, DeclContext *DC, SourceLocation SL,
+ ArrayRef<TemplateArgument> ConvertedArgs) {
+ return new (C, DC,
+ additionalSizeToAlloc<TemplateArgument>(ConvertedArgs.size()))
+ ImplicitConceptSpecializationDecl(DC, SL, ConvertedArgs);
+}
+
+ImplicitConceptSpecializationDecl *
+ImplicitConceptSpecializationDecl::CreateDeserialized(
+ const ASTContext &C, unsigned ID, unsigned NumTemplateArgs) {
+ return new (C, ID, additionalSizeToAlloc<TemplateArgument>(NumTemplateArgs))
+ ImplicitConceptSpecializationDecl(EmptyShell{}, NumTemplateArgs);
+}
+
+void ImplicitConceptSpecializationDecl::setTemplateArguments(
+ ArrayRef<TemplateArgument> Converted) {
+ assert(Converted.size() == NumTemplateArgs);
+ std::uninitialized_copy(Converted.begin(), Converted.end(),
+ getTrailingObjects<TemplateArgument>());
+}
+
//===----------------------------------------------------------------------===//
// ClassTemplatePartialSpecializationDecl Implementation
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/AST/ExprConcepts.cpp b/clang/lib/AST/ExprConcepts.cpp
index c17453fb45fb8..fc8f1eb2abf14 100644
--- a/clang/lib/AST/ExprConcepts.cpp
+++ b/clang/lib/AST/ExprConcepts.cpp
@@ -35,16 +35,15 @@ ConceptSpecializationExpr::ConceptSpecializationExpr(
SourceLocation TemplateKWLoc, DeclarationNameInfo ConceptNameInfo,
NamedDecl *FoundDecl, ConceptDecl *NamedConcept,
const ASTTemplateArgumentListInfo *ArgsAsWritten,
- ArrayRef<TemplateArgument> ConvertedArgs,
+ ImplicitConceptSpecializationDecl *SpecDecl,
const ConstraintSatisfaction *Satisfaction)
: Expr(ConceptSpecializationExprClass, C.BoolTy, VK_PRValue, OK_Ordinary),
ConceptReference(NNS, TemplateKWLoc, ConceptNameInfo, FoundDecl,
NamedConcept, ArgsAsWritten),
- NumTemplateArgs(ConvertedArgs.size()),
+ SpecDecl(SpecDecl),
Satisfaction(Satisfaction
? ASTConstraintSatisfaction::Create(C, *Satisfaction)
: nullptr) {
- setTemplateArguments(ConvertedArgs);
setDependence(computeDependence(this, /*ValueDependent=*/!Satisfaction));
// Currently guaranteed by the fact concepts can only be at namespace-scope.
@@ -56,50 +55,34 @@ ConceptSpecializationExpr::ConceptSpecializationExpr(
"should not be value-dependent");
}
-ConceptSpecializationExpr::ConceptSpecializationExpr(EmptyShell Empty,
- unsigned NumTemplateArgs)
- : Expr(ConceptSpecializationExprClass, Empty),
- NumTemplateArgs(NumTemplateArgs) {}
+ConceptSpecializationExpr::ConceptSpecializationExpr(EmptyShell Empty)
+ : Expr(ConceptSpecializationExprClass, Empty) {}
-void ConceptSpecializationExpr::setTemplateArguments(
- ArrayRef<TemplateArgument> Converted) {
- assert(Converted.size() == NumTemplateArgs);
- std::uninitialized_copy(Converted.begin(), Converted.end(),
- getTrailingObjects<TemplateArgument>());
-}
-
-ConceptSpecializationExpr *
-ConceptSpecializationExpr::Create(const ASTContext &C,
- NestedNameSpecifierLoc NNS,
- SourceLocation TemplateKWLoc,
- DeclarationNameInfo ConceptNameInfo,
- NamedDecl *FoundDecl,
- ConceptDecl *NamedConcept,
- const ASTTemplateArgumentListInfo *ArgsAsWritten,
- ArrayRef<TemplateArgument> ConvertedArgs,
- const ConstraintSatisfaction *Satisfaction) {
- void *Buffer = C.Allocate(totalSizeToAlloc<TemplateArgument>(
- ConvertedArgs.size()));
- return new (Buffer) ConceptSpecializationExpr(C, NNS, TemplateKWLoc,
- ConceptNameInfo, FoundDecl,
- NamedConcept, ArgsAsWritten,
- ConvertedArgs, Satisfaction);
+ConceptSpecializationExpr *ConceptSpecializationExpr::Create(
+ const ASTContext &C, NestedNameSpecifierLoc NNS,
+ SourceLocation TemplateKWLoc, DeclarationNameInfo ConceptNameInfo,
+ NamedDecl *FoundDecl, ConceptDecl *NamedConcept,
+ const ASTTemplateArgumentListInfo *ArgsAsWritten,
+ ImplicitConceptSpecializationDecl *SpecDecl,
+ const ConstraintSatisfaction *Satisfaction) {
+ return new (C) ConceptSpecializationExpr(
+ C, NNS, TemplateKWLoc, ConceptNameInfo, FoundDecl, NamedConcept,
+ ArgsAsWritten, SpecDecl, Satisfaction);
}
ConceptSpecializationExpr::ConceptSpecializationExpr(
const ASTContext &C, ConceptDecl *NamedConcept,
- ArrayRef<TemplateArgument> ConvertedArgs,
+ ImplicitConceptSpecializationDecl *SpecDecl,
const ConstraintSatisfaction *Satisfaction, bool Dependent,
bool ContainsUnexpandedParameterPack)
: Expr(ConceptSpecializationExprClass, C.BoolTy, VK_PRValue, OK_Ordinary),
ConceptReference(NestedNameSpecifierLoc(), SourceLocation(),
DeclarationNameInfo(), NamedConcept, NamedConcept,
nullptr),
- NumTemplateArgs(ConvertedArgs.size()),
+ SpecDecl(SpecDecl),
Satisfaction(Satisfaction
? ASTConstraintSatisfaction::Create(C, *Satisfaction)
: nullptr) {
- setTemplateArguments(ConvertedArgs);
ExprDependence D = ExprDependence::None;
if (!Satisfaction)
D |= ExprDependence::Value;
@@ -110,26 +93,14 @@ ConceptSpecializationExpr::ConceptSpecializationExpr(
setDependence(D);
}
-ConceptSpecializationExpr *
-ConceptSpecializationExpr::Create(const ASTContext &C,
- ConceptDecl *NamedConcept,
- ArrayRef<TemplateArgument> ConvertedArgs,
- const ConstraintSatisfaction *Satisfaction,
- bool Dependent,
- bool ContainsUnexpandedParameterPack) {
- void *Buffer = C.Allocate(totalSizeToAlloc<TemplateArgument>(
- ConvertedArgs.size()));
- return new (Buffer) ConceptSpecializationExpr(
- C, NamedConcept, ConvertedArgs, Satisfaction, Dependent,
- ContainsUnexpandedParameterPack);
-}
-
-ConceptSpecializationExpr *
-ConceptSpecializationExpr::Create(ASTContext &C, EmptyShell Empty,
- unsigned NumTemplateArgs) {
- void *Buffer = C.Allocate(totalSizeToAlloc<TemplateArgument>(
- NumTemplateArgs));
- return new (Buffer) ConceptSpecializationExpr(Empty, NumTemplateArgs);
+ConceptSpecializationExpr *ConceptSpecializationExpr::Create(
+ const ASTContext &C, ConceptDecl *NamedConcept,
+ ImplicitConceptSpecializationDecl *SpecDecl,
+ const ConstraintSatisfaction *Satisfaction, bool Dependent,
+ bool ContainsUnexpandedParameterPack) {
+ return new (C)
+ ConceptSpecializationExpr(C, NamedConcept, SpecDecl, Satisfaction,
+ Dependent, ContainsUnexpandedParameterPack);
}
const TypeConstraint *
diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp
index 8f28f96e93785..2bf104b58d947 100644
--- a/clang/lib/CodeGen/CGDecl.cpp
+++ b/clang/lib/CodeGen/CGDecl.cpp
@@ -127,6 +127,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
case Decl::OMPRequires:
case Decl::Empty:
case Decl::Concept:
+ case Decl::ImplicitConceptSpecialization:
case Decl::LifetimeExtendedTemporary:
case Decl::RequiresExprBody:
// None of these decls require codegen support.
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 484c02498f20b..e5ee950e67997 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -265,7 +265,8 @@ static ExprResult calculateConstraintSatisfaction(
return calculateConstraintSatisfaction(
S, ConstraintExpr, Satisfaction, [&](const Expr *AtomicExpr) {
EnterExpressionEvaluationContext ConstantEvaluated(
- S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
+ S, Sema::ExpressionEvaluationContext::ConstantEvaluated,
+ Sema::ReuseLambdaContextDecl);
// Atomic constraint - substitute arguments and check satisfaction.
ExprResult SubstitutedExpression;
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index 2143b811668af..a22708df5dbed 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -282,7 +282,8 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC) {
DataMember,
StaticDataMember,
InlineVariable,
- VariableTemplate
+ VariableTemplate,
+ Concept
} Kind = Normal;
// Default arguments of member function parameters that appear in a class
@@ -307,6 +308,8 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC) {
}
} else if (isa<FieldDecl>(ManglingContextDecl)) {
Kind = DataMember;
+ } else if (isa<ImplicitConceptSpecializationDecl>(ManglingContextDecl)) {
+ Kind = Concept;
}
}
@@ -330,6 +333,11 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC) {
return std::make_tuple(nullptr, nullptr);
}
+ case Concept:
+ // Concept definitions aren't code generated and thus aren't mangled,
+ // however the ManglingContextDecl is important for the purposes of
+ // re-forming the template argument list of the lambda for constraint
+ // evaluation.
case StaticDataMember:
// -- the initializers of nonspecialized static members of template classes
if (!IsInNonspecializedTemplate)
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index f6627c9bc53c3..d81ed15f979f1 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -4866,6 +4866,9 @@ Sema::CheckConceptTemplateId(const CXXScopeSpec &SS,
/*UpdateArgsWithConversions=*/false))
return ExprError();
+ auto *CSD = ImplicitConceptSpecializationDecl::Create(
+ Context, NamedConcept->getDeclContext(), NamedConcept->getLocation(),
+ Converted);
ConstraintSatisfaction Satisfaction;
bool AreArgsDependent =
TemplateSpecializationType::anyDependentTemplateArguments(*TemplateArgs,
@@ -4873,6 +4876,10 @@ Sema::CheckConceptTemplateId(const CXXScopeSpec &SS,
MultiLevelTemplateArgumentList MLTAL;
MLTAL.addOuterTemplateArguments(NamedConcept, Converted);
LocalInstantiationScope Scope(*this);
+
+ EnterExpressionEvaluationContext EECtx{
+ *this, ExpressionEvaluationContext::ConstantEvaluated, CSD};
+
if (!AreArgsDependent &&
CheckConstraintSatisfaction(
NamedConcept, {NamedConcept->getConstraintExpr()}, MLTAL,
@@ -4881,10 +4888,11 @@ Sema::CheckConceptTemplateId(const CXXScopeSpec &SS,
Satisfaction))
return ExprError();
- return ConceptSpecializationExpr::Create(Context,
+ return ConceptSpecializationExpr::Create(
+ Context,
SS.isSet() ? SS.getWithLocInContext(Context) : NestedNameSpecifierLoc{},
TemplateKWLoc, ConceptNameInfo, FoundDecl, NamedConcept,
- ASTTemplateArgumentListInfo::Create(Context, *TemplateArgs), Converted,
+ ASTTemplateArgumentListInfo::Create(Context, *TemplateArgs), CSD,
AreArgsDependent ? nullptr : &Satisfaction);
}
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 1400693f664ea..7475289745c7d 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -231,6 +231,15 @@ Response HandleRecordDecl(const CXXRecordDecl *Rec,
return Response::UseNextDecl(Rec);
}
+Response HandleImplicitConceptSpecializationDecl(
+ const ImplicitConceptSpecializationDecl *CSD,
+ MultiLevelTemplateArgumentList &Result) {
+ Result.addOuterTemplateArguments(
+ const_cast<ImplicitConceptSpecializationDecl *>(CSD),
+ CSD->getTemplateArguments());
+ return Response::UseNextDecl(CSD);
+}
+
Response HandleGenericDeclContext(const Decl *CurDecl) {
return Response::UseNextDecl(CurDecl);
}
@@ -289,6 +298,9 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
ForConstraintInstantiation);
} else if (const auto *Rec = dyn_cast<CXXRecordDecl>(CurDecl)) {
R = HandleRecordDecl(Rec, Result, Context, ForConstraintInstantiation);
+ } else if (const auto *CSD =
+ dyn_cast<ImplicitConceptSpecializationDecl>(CurDecl)) {
+ R = HandleImplicitConceptSpecializationDecl(CSD, Result);
} else if (!isa<DeclContext>(CurDecl)) {
R = Response::DontClearRelativeToPrimaryNextDecl(CurDecl);
if (CurDecl->getDeclContext()->isTranslationUnit()) {
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 2c7fc8d56dbdb..dc694b2cb7c97 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -3965,6 +3965,11 @@ Decl *TemplateDeclInstantiator::VisitConceptDecl(ConceptDecl *D) {
llvm_unreachable("Concept definitions cannot reside inside a template");
}
+Decl *TemplateDeclInstantiator::VisitImplicitConceptSpecializationDecl(
+ ImplicitConceptSpecializationDecl *D) {
+ llvm_unreachable("Concept specializations cannot reside inside a template");
+}
+
Decl *
TemplateDeclInstantiator::VisitRequiresExprBodyDecl(RequiresExprBodyDecl *D) {
return RequiresExprBodyDecl::Create(SemaRef.Context, D->getDeclContext(),
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 4f6ee0772c3c7..ebb83f12b6566 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -12606,7 +12606,8 @@ TreeTransform<Derived>::TransformRequiresExpr(RequiresExpr *E) {
// C++2a [expr.prim.req]p2
// Expressions appearing within a requirement-body are unevaluated operands.
EnterExpressionEvaluationContext Ctx(
- SemaRef, Sema::ExpressionEvaluationContext::Unevaluated);
+ SemaRef, Sema::ExpressionEvaluationContext::Unevaluated,
+ Sema::ReuseLambdaContextDecl);
RequiresExprBodyDecl *Body = RequiresExprBodyDecl::Create(
getSema().Context, getSema().CurContext,
diff --git a/clang/lib/Serialization/ASTCommon.cpp b/clang/lib/Serialization/ASTCommon.cpp
index 53e4c889f5298..152037dfc9269 100644
--- a/clang/lib/Serialization/ASTCommon.cpp
+++ b/clang/lib/Serialization/ASTCommon.cpp
@@ -430,6 +430,7 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) {
case Decl::Decomposition:
case Decl::Binding:
case Decl::Concept:
+ case Decl::ImplicitConceptSpecialization:
case Decl::LifetimeExtendedTemporary:
case Decl::RequiresExprBody:
case Decl::UnresolvedUsingIfExists:
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index 36629101b7de4..94a1d243918dd 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -384,6 +384,8 @@ namespace clang {
void VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D);
void VisitTemplateDecl(TemplateDecl *D);
void VisitConceptDecl(ConceptDecl *D);
+ void VisitImplicitConceptSpecializationDecl(
+ ImplicitConceptSpecializationDecl *D);
void VisitRequiresExprBodyDecl(RequiresExprBodyDecl *D);
RedeclarableResult VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D);
void VisitClassTemplateDecl(ClassTemplateDecl *D);
@@ -2234,6 +2236,17 @@ void ASTDeclReader::VisitConceptDecl(ConceptDecl *D) {
mergeMergeable(D);
}
+void ASTDeclReader::VisitImplicitConceptSpecializationDecl(
+ ImplicitConceptSpecializationDecl *D) {
+ // The size of the template list was read during creation of the Decl, so we
+ // don't have to re-read it here.
+ VisitDecl(D);
+ llvm::SmallVector<TemplateArgument, 4> Args;
+ for (unsigned I = 0; I < D->NumTemplateArgs; ++I)
+ Args.push_back(Record.readTemplateArgument(/*Canonicalize=*/true));
+ D->setTemplateArguments(Args);
+}
+
void ASTDeclReader::VisitRequiresExprBodyDecl(RequiresExprBodyDecl *D) {
}
@@ -3900,6 +3913,10 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
case DECL_HLSL_BUFFER:
D = HLSLBufferDecl::CreateDeserialized(Context, ID);
break;
+ case DECL_IMPLICIT_CONCEPT_SPECIALIZATION:
+ D = ImplicitConceptSpecializationDecl::CreateDeserialized(Context, ID,
+ Record.readInt());
+ break;
}
assert(D && "Unknown declaration reading AST file");
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp
index 98b8a960aef7c..f6a2f85682b2a 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -794,17 +794,13 @@ readConstraintSatisfaction(ASTRecordReader &Record) {
void ASTStmtReader::VisitConceptSpecializationExpr(
ConceptSpecializationExpr *E) {
VisitExpr(E);
- unsigned NumTemplateArgs = Record.readInt();
E->NestedNameSpec = Record.readNestedNameSpecifierLoc();
E->TemplateKWLoc = Record.readSourceLocation();
E->ConceptName = Record.readDeclarationNameInfo();
E->NamedConcept = readDeclAs<ConceptDecl>();
E->FoundDecl = Record.readDeclAs<NamedDecl>();
+ E->SpecDecl = Record.readDeclAs<ImplicitConceptSpecializationDecl>();
E->ArgsAsWritten = Record.readASTTemplateArgumentListInfo();
- llvm::SmallVector<TemplateArgument, 4> Args;
- for (unsigned I = 0; I < NumTemplateArgs; ++I)
- Args.push_back(Record.readTemplateArgument(/*Canonicalize*/ true));
- E->setTemplateArguments(Args);
E->Satisfaction = E->isValueDependent() ? nullptr :
ASTConstraintSatisfaction::Create(Record.getContext(),
readConstraintSatisfaction(Record));
@@ -4003,8 +3999,7 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
break;
case EXPR_CONCEPT_SPECIALIZATION: {
- unsigned numTemplateArgs = Record[ASTStmtReader::NumExprFields];
- S = ConceptSpecializationExpr::Create(Context, Empty, numTemplateArgs);
+ S = new (Context) ConceptSpecializationExpr(Empty);
break;
}
diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp
index afe59ef98c8e2..93785eeb9e880 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -107,6 +107,8 @@ namespace clang {
void VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D);
void VisitTemplateDecl(TemplateDecl *D);
void VisitConceptDecl(ConceptDecl *D);
+ void VisitImplicitConceptSpecializationDecl(
+ ImplicitConceptSpecializationDecl *D);
void VisitRequiresExprBodyDecl(RequiresExprBodyDecl *D);
void VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D);
void VisitClassTemplateDecl(ClassTemplateDecl *D);
@@ -1517,6 +1519,15 @@ void ASTDeclWriter::VisitConceptDecl(ConceptDecl *D) {
Code = serialization::DECL_CONCEPT;
}
+void ASTDeclWriter::VisitImplicitConceptSpecializationDecl(
+ ImplicitConceptSpecializationDecl *D) {
+ Record.push_back(D->getTemplateArguments().size());
+ VisitDecl(D);
+ for (const TemplateArgument &Arg : D->getTemplateArguments())
+ Record.AddTemplateArgument(Arg);
+ Code = serialization::DECL_IMPLICIT_CONCEPT_SPECIALIZATION;
+}
+
void ASTDeclWriter::VisitRequiresExprBodyDecl(RequiresExprBodyDecl *D) {
Code = serialization::DECL_REQUIRES_EXPR_BODY;
}
diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp
index 65761566ab060..be28ad6b2a668 100644
--- a/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -433,16 +433,13 @@ addSubstitutionDiagnostic(
void ASTStmtWriter::VisitConceptSpecializationExpr(
ConceptSpecializationExpr *E) {
VisitExpr(E);
- ArrayRef<TemplateArgument> TemplateArgs = E->getTemplateArguments();
- Record.push_back(TemplateArgs.size());
Record.AddNestedNameSpecifierLoc(E->getNestedNameSpecifierLoc());
Record.AddSourceLocation(E->getTemplateKWLoc());
Record.AddDeclarationNameInfo(E->getConceptNameInfo());
Record.AddDeclRef(E->getNamedConcept());
Record.AddDeclRef(E->getFoundDecl());
+ Record.AddDeclRef(E->getSpecializationDecl());
Record.AddASTTemplateArgumentListInfo(E->getTemplateArgsAsWritten());
- for (const TemplateArgument &Arg : TemplateArgs)
- Record.AddTemplateArgument(Arg);
if (!E->isValueDependent())
addConstraintSatisfaction(Record, E->getSatisfaction());
diff --git a/clang/test/AST/ast-dump-concepts.cpp b/clang/test/AST/ast-dump-concepts.cpp
index dff300a559517..06518a71987a2 100644
--- a/clang/test/AST/ast-dump-concepts.cpp
+++ b/clang/test/AST/ast-dump-concepts.cpp
@@ -19,6 +19,11 @@ template <typename T>
struct Foo {
// CHECK: TemplateTypeParmDecl {{.*}} referenced Concept {{.*}} 'binary_concept'
// CHECK-NEXT: `-ConceptSpecializationExpr {{.*}} <col:13, col:31> 'bool' Concept {{.*}} 'binary_concept'
+ // CHECK-NEXT: |-ImplicitConceptSpecializationDecl {{.*}} <line:13:9> col:9
+ // CHECK-NEXT: | |-TemplateArgument type 'type-parameter-1-0'
+ // CHECK-NEXT: | | `-TemplateTypeParmType {{.*}} 'type-parameter-1-0' dependent {{.*}}depth 1 index 0
+ // CHECK-NEXT: | `-TemplateArgument type 'int'
+ // CHECK-NEXT: | `-BuiltinType {{.*}} 'int'
// CHECK-NEXT: |-TemplateArgument {{.*}} type 'R'
// CHECK-NEXT: | `-TemplateTypeParmType {{.*}} 'R'
// CHECK-NEXT: | `-TemplateTypeParm {{.*}} 'R'
@@ -29,6 +34,9 @@ struct Foo {
// CHECK: TemplateTypeParmDecl {{.*}} referenced Concept {{.*}} 'unary_concept'
// CHECK-NEXT: `-ConceptSpecializationExpr {{.*}} <col:13> 'bool'
+ // CHECK-NEXT: |-ImplicitConceptSpecializationDecl {{.*}} <line:10:9> col:9
+ // CHECK-NEXT: | `-TemplateArgument type 'type-parameter-1-0'
+ // CHECK-NEXT: | `-TemplateTypeParmType {{.*}} 'type-parameter-1-0' dependent {{.*}}depth 1 index 0
template <unary_concept R>
Foo(R);
diff --git a/clang/test/SemaTemplate/concepts-lambda.cpp b/clang/test/SemaTemplate/concepts-lambda.cpp
index 13c402e3ca7a8..a4e8e0e50f026 100644
--- a/clang/test/SemaTemplate/concepts-lambda.cpp
+++ b/clang/test/SemaTemplate/concepts-lambda.cpp
@@ -55,3 +55,39 @@ namespace GH57971 {
using function_ptr = void(*)(int);
function_ptr ptr = f<void>;
}
+
+// GH58368: A lambda defined in a concept requires we store
+// the concept as a part of the lambda context.
+namespace LambdaInConcept {
+using size_t = unsigned long;
+
+template<size_t...Ts>
+struct IdxSeq{};
+
+template <class T, class... Ts>
+concept NotLike = true;
+
+template <size_t, class... Ts>
+struct AnyExcept {
+ template <NotLike<Ts...> T> operator T&() const;
+ template <NotLike<Ts...> T> operator T&&() const;
+};
+
+template <class T>
+ concept ConstructibleWithN = (requires {
+ []<size_t I, size_t... Idxs>
+ (IdxSeq<I, Idxs...>)
+ requires requires { T{AnyExcept<I, T>{}}; }
+ { }
+ (IdxSeq<1,2,3>{});
+ });
+
+struct Foo {
+ int i;
+ double j;
+ char k;
+};
+
+static_assert(ConstructibleWithN<Foo>);
+
+}
diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp
index 69d34646ca937..9cdbddd82f76c 100644
--- a/clang/tools/libclang/CIndex.cpp
+++ b/clang/tools/libclang/CIndex.cpp
@@ -6700,6 +6700,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
case Decl::PragmaDetectMismatch:
case Decl::UsingPack:
case Decl::Concept:
+ case Decl::ImplicitConceptSpecialization:
case Decl::LifetimeExtendedTemporary:
case Decl::RequiresExprBody:
case Decl::UnresolvedUsingIfExists:
More information about the cfe-commits
mailing list