[clang] [Clang] Bugfixes and improved support for `AttributedType`s in lambdas (PR #85325)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Mar 14 16:55:43 PDT 2024
https://github.com/Sirraide updated https://github.com/llvm/llvm-project/pull/85325
>From 907210a3ad3d829a8e49a5c976d129f8653801bf Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Thu, 14 Mar 2024 18:24:37 +0100
Subject: [PATCH 1/9] [Clang] Add `dump()` method for `Attr`
---
clang/include/clang/AST/Attr.h | 2 ++
clang/lib/AST/ASTDumper.cpp | 8 ++++++++
2 files changed, 10 insertions(+)
diff --git a/clang/include/clang/AST/Attr.h b/clang/include/clang/AST/Attr.h
index 8e9b7ad8b46826..6400023947863f 100644
--- a/clang/include/clang/AST/Attr.h
+++ b/clang/include/clang/AST/Attr.h
@@ -112,6 +112,8 @@ class Attr : public AttributeCommonInfo {
// Pretty print this attribute.
void printPretty(raw_ostream &OS, const PrintingPolicy &Policy) const;
+ void dump() const;
+
static StringRef getDocumentation(attr::Kind);
};
diff --git a/clang/lib/AST/ASTDumper.cpp b/clang/lib/AST/ASTDumper.cpp
index 6efc5bb92e28d2..8d8b8621341ef7 100644
--- a/clang/lib/AST/ASTDumper.cpp
+++ b/clang/lib/AST/ASTDumper.cpp
@@ -361,3 +361,11 @@ LLVM_DUMP_METHOD void ConceptReference::dump(raw_ostream &OS) const {
ASTDumper P(OS, Ctx, Ctx.getDiagnostics().getShowColors());
P.Visit(this);
}
+
+//===----------------------------------------------------------------------===//
+// Attr method implementations
+//===----------------------------------------------------------------------===//
+LLVM_DUMP_METHOD void Attr::dump() const {
+ ASTDumper P(llvm::errs(), /*ShowColors=*/false);
+ P.Visit(this);
+}
>From d719a7605c89ed4ea88734b5386b6009931450f6 Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Thu, 14 Mar 2024 18:25:18 +0100
Subject: [PATCH 2/9] [Clang] Do not instantiate the same (FunctionProto)Type
twice
---
clang/lib/Sema/TreeTransform.h | 22 ++++++++++++++++------
1 file changed, 16 insertions(+), 6 deletions(-)
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 2d22692f3ab750..cf781792935f18 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -7231,12 +7231,22 @@ QualType TreeTransform<Derived>::TransformAttributedType(
// FIXME: dependent operand expressions?
if (getDerived().AlwaysRebuild() ||
modifiedType != oldType->getModifiedType()) {
- TypeLocBuilder AuxiliaryTLB;
- AuxiliaryTLB.reserve(TL.getFullDataSize());
- QualType equivalentType =
- getDerived().TransformType(AuxiliaryTLB, TL.getEquivalentTypeLoc());
- if (equivalentType.isNull())
- return QualType();
+ // Do not transform the equivalent type if it is equal to the modified type.
+ //
+ // This is because, 1. it’s the same type, instantiating it again will yield
+ // the same result anyway, and if it doesn't, then that could be a bug in
+ // and of itself, and 2. instantiating the same TypeLoc twice is a really
+ // bad idea if it's a FunctionProtoType, because instantiating the same
+ // ParmVarDecls twice will cause assertion failures.
+ QualType equivalentType = modifiedType;
+ if (TL.getModifiedLoc().getType() != TL.getEquivalentTypeLoc().getType()) {
+ TypeLocBuilder AuxiliaryTLB;
+ AuxiliaryTLB.reserve(TL.getFullDataSize());
+ equivalentType =
+ getDerived().TransformType(AuxiliaryTLB, TL.getEquivalentTypeLoc());
+ if (equivalentType.isNull())
+ return QualType();
+ }
// Check whether we can add nullability; it is only represented as
// type sugar, and therefore cannot be diagnosed in any other way.
>From a9c753ab46b40bd7da6f27eb11655fe43acb11de Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Thu, 14 Mar 2024 21:40:41 +0100
Subject: [PATCH 3/9] [Clang] Refactor instantiation of a lambda's
FunctionProtoType
---------
Co-authored-by: Yuxuan Chen <ych at meta.com>
---
clang/include/clang/Sema/Template.h | 14 +++-
clang/lib/Sema/SemaTemplateInstantiate.cpp | 13 +++-
clang/lib/Sema/TreeTransform.h | 90 +++++++---------------
3 files changed, 49 insertions(+), 68 deletions(-)
diff --git a/clang/include/clang/Sema/Template.h b/clang/include/clang/Sema/Template.h
index ce44aca797b0fb..8c379f51ca3d5d 100644
--- a/clang/include/clang/Sema/Template.h
+++ b/clang/include/clang/Sema/Template.h
@@ -411,6 +411,11 @@ enum class TemplateSubstitutionKind : char {
/// lookup will search our outer scope.
bool CombineWithOuterScope;
+ /// Whether this scope is being used to instantiate a lambda expression,
+ /// in which case it should be reused for instantiating the lambda's
+ /// FunctionProtoType.
+ bool InstantiatingLambda = false;
+
/// If non-NULL, the template parameter pack that has been
/// partially substituted per C++0x [temp.arg.explicit]p9.
NamedDecl *PartiallySubstitutedPack = nullptr;
@@ -425,9 +430,11 @@ enum class TemplateSubstitutionKind : char {
unsigned NumArgsInPartiallySubstitutedPack;
public:
- LocalInstantiationScope(Sema &SemaRef, bool CombineWithOuterScope = false)
+ LocalInstantiationScope(Sema &SemaRef, bool CombineWithOuterScope = false,
+ bool InstantiatingLambda = false)
: SemaRef(SemaRef), Outer(SemaRef.CurrentInstantiationScope),
- CombineWithOuterScope(CombineWithOuterScope) {
+ CombineWithOuterScope(CombineWithOuterScope),
+ InstantiatingLambda(InstantiatingLambda) {
SemaRef.CurrentInstantiationScope = this;
}
@@ -553,6 +560,9 @@ enum class TemplateSubstitutionKind : char {
/// Determine whether D is a pack expansion created in this scope.
bool isLocalPackExpansion(const Decl *D);
+
+ /// Determine whether this scope is for instantiating a lambda.
+ bool isLambda() const { return InstantiatingLambda; }
};
class TemplateDeclInstantiator
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 1a0c88703aca01..6c753c9956bddb 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1535,7 +1535,8 @@ namespace {
bool SuppressObjCLifetime);
ExprResult TransformLambdaExpr(LambdaExpr *E) {
- LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true);
+ LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true,
+ /*InstantiatingLambda=*/true);
Sema::ConstraintEvalRAII<TemplateInstantiator> RAII(*this);
ExprResult Result = inherited::TransformLambdaExpr(E);
@@ -2276,8 +2277,14 @@ QualType TemplateInstantiator::TransformFunctionProtoType(TypeLocBuilder &TLB,
CXXRecordDecl *ThisContext,
Qualifiers ThisTypeQuals,
Fn TransformExceptionSpec) {
- // We need a local instantiation scope for this function prototype.
- LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true);
+ // If this is a lambda, then TemplateInstantiator::TransformLambdaExpr will
+ // have already pushed a scope for this prototype, so don't create a second
+ // one. Otherwise, push a new instantiation scope.
+ LocalInstantiationScope *Current = getSema().CurrentInstantiationScope;
+ std::optional<LocalInstantiationScope> Scope;
+ if (!Current || !Current->isLambda())
+ Scope.emplace(SemaRef, /*CombineWithOuterScope=*/true);
+
return inherited::TransformFunctionProtoType(
TLB, TL, ThisContext, ThisTypeQuals, TransformExceptionSpec);
}
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index cf781792935f18..b129f3db2b7a64 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -675,10 +675,6 @@ class TreeTransform {
Qualifiers ThisTypeQuals,
Fn TransformExceptionSpec);
- template <typename Fn>
- QualType TransformAttributedType(TypeLocBuilder &TLB, AttributedTypeLoc TL,
- Fn TransformModifiedType);
-
bool TransformExceptionSpec(SourceLocation Loc,
FunctionProtoType::ExceptionSpecInfo &ESI,
SmallVectorImpl<QualType> &Exceptions,
@@ -7212,11 +7208,10 @@ TreeTransform<Derived>::TransformElaboratedType(TypeLocBuilder &TLB,
}
template <typename Derived>
-template <typename Fn>
QualType TreeTransform<Derived>::TransformAttributedType(
- TypeLocBuilder &TLB, AttributedTypeLoc TL, Fn TransformModifiedTypeFn) {
+ TypeLocBuilder &TLB, AttributedTypeLoc TL) {
const AttributedType *oldType = TL.getTypePtr();
- QualType modifiedType = TransformModifiedTypeFn(TLB, TL.getModifiedLoc());
+ QualType modifiedType = getDerived().TransformType(TLB, TL.getModifiedLoc());
if (modifiedType.isNull())
return QualType();
@@ -7270,15 +7265,6 @@ QualType TreeTransform<Derived>::TransformAttributedType(
return result;
}
-template <typename Derived>
-QualType TreeTransform<Derived>::TransformAttributedType(TypeLocBuilder &TLB,
- AttributedTypeLoc TL) {
- return getDerived().TransformAttributedType(
- TLB, TL, [&](TypeLocBuilder &TLB, TypeLoc ModifiedLoc) -> QualType {
- return getDerived().TransformType(TLB, ModifiedLoc);
- });
-}
-
template <typename Derived>
QualType TreeTransform<Derived>::TransformBTFTagAttributedType(
TypeLocBuilder &TLB, BTFTagAttributedTypeLoc TL) {
@@ -13840,62 +13826,40 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
getSema().AddTemplateParametersToLambdaCallOperator(NewCallOperator, Class,
TPL);
- // Transform the type of the original lambda's call operator.
- // The transformation MUST be done in the CurrentInstantiationScope since
- // it introduces a mapping of the original to the newly created
- // transformed parameters.
TypeSourceInfo *NewCallOpTSI = nullptr;
- {
- auto OldCallOpTypeLoc =
- E->getCallOperator()->getTypeSourceInfo()->getTypeLoc();
-
- auto TransformFunctionProtoTypeLoc =
- [this](TypeLocBuilder &TLB, FunctionProtoTypeLoc FPTL) -> QualType {
- SmallVector<QualType, 4> ExceptionStorage;
- return this->TransformFunctionProtoType(
- TLB, FPTL, nullptr, Qualifiers(),
- [&](FunctionProtoType::ExceptionSpecInfo &ESI, bool &Changed) {
- return TransformExceptionSpec(FPTL.getBeginLoc(), ESI,
- ExceptionStorage, Changed);
- });
- };
-
- QualType NewCallOpType;
- TypeLocBuilder NewCallOpTLBuilder;
-
- if (auto ATL = OldCallOpTypeLoc.getAs<AttributedTypeLoc>()) {
- NewCallOpType = this->TransformAttributedType(
- NewCallOpTLBuilder, ATL,
- [&](TypeLocBuilder &TLB, TypeLoc TL) -> QualType {
- return TransformFunctionProtoTypeLoc(
- TLB, TL.castAs<FunctionProtoTypeLoc>());
- });
- } else {
- auto FPTL = OldCallOpTypeLoc.castAs<FunctionProtoTypeLoc>();
- NewCallOpType = TransformFunctionProtoTypeLoc(NewCallOpTLBuilder, FPTL);
- }
+ auto OldCallOpTypeLoc =
+ E->getCallOperator()->getTypeSourceInfo()->getTypeLoc();
- if (NewCallOpType.isNull())
- return ExprError();
- NewCallOpTSI =
- NewCallOpTLBuilder.getTypeSourceInfo(getSema().Context, NewCallOpType);
- }
+ QualType NewCallOpType;
+ TypeLocBuilder NewCallOpTLBuilder;
- ArrayRef<ParmVarDecl *> Params;
- if (auto ATL = NewCallOpTSI->getTypeLoc().getAs<AttributedTypeLoc>()) {
- Params = ATL.getModifiedLoc().castAs<FunctionProtoTypeLoc>().getParams();
- } else {
- auto FPTL = NewCallOpTSI->getTypeLoc().castAs<FunctionProtoTypeLoc>();
- Params = FPTL.getParams();
- }
+ NewCallOpType =
+ getDerived().TransformType(NewCallOpTLBuilder, OldCallOpTypeLoc);
+ if (NewCallOpType.isNull())
+ return ExprError();
+ NewCallOpTSI =
+ NewCallOpTLBuilder.getTypeSourceInfo(getSema().Context, NewCallOpType);
+
+ auto ExtractParams = [](TypeLoc TL) {
+ auto Impl = [](auto Self, TypeLoc TL) -> ArrayRef<ParmVarDecl *> {
+ if (auto FPTL = TL.getAs<FunctionProtoTypeLoc>())
+ return FPTL.getParams();
+ if (auto ATL = TL.getAs<AttributedTypeLoc>())
+ return Self(Self, ATL.getModifiedLoc());
+ if (auto MQTL = TL.getAs<MacroQualifiedTypeLoc>())
+ return Self(Self, MQTL.getInnerLoc());
+ llvm_unreachable("Unhandled TypeLoc");
+ };
+ return Impl(Impl, TL);
+ };
getSema().CompleteLambdaCallOperator(
NewCallOperator, E->getCallOperator()->getLocation(),
E->getCallOperator()->getInnerLocStart(),
E->getCallOperator()->getTrailingRequiresClause(), NewCallOpTSI,
E->getCallOperator()->getConstexprKind(),
- E->getCallOperator()->getStorageClass(), Params,
- E->hasExplicitResultType());
+ E->getCallOperator()->getStorageClass(),
+ ExtractParams(NewCallOpTSI->getTypeLoc()), E->hasExplicitResultType());
getDerived().transformAttrs(E->getCallOperator(), NewCallOperator);
getDerived().transformedLocalDecl(E->getCallOperator(), {NewCallOperator});
>From 4a0878a48682da48eb7fd906a899c1be45d0510e Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Thu, 14 Mar 2024 21:45:20 +0100
Subject: [PATCH 4/9] [Clang] Preserve type sugar in more places
---------
Co-authored-by: Doug Wyatt <dwyatt at apple.com>
---
clang/include/clang/AST/ASTContext.h | 5 ++++
clang/lib/AST/ASTContext.cpp | 27 ++++++++++++++++---
.../test/SemaCXX/lambda-conversion-op-cc.cpp | 10 +++----
3 files changed, 34 insertions(+), 8 deletions(-)
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index ff6b64c7f72d57..46165f4d4fd547 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -1295,6 +1295,11 @@ class ASTContext : public RefCountedBase<ASTContext> {
const FunctionType *adjustFunctionType(const FunctionType *Fn,
FunctionType::ExtInfo EInfo);
+ /// Change the result type of a function type, preserving sugar such as
+ /// attributed types.
+ QualType adjustFunctionResultType(QualType FunctionType,
+ QualType NewResultType);
+
/// Adjust the given function result type.
CanQualType getCanonicalFunctionResultType(QualType ResultType) const;
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 5a8fae76a43a4d..16cfae0627d66c 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -3140,13 +3140,34 @@ const FunctionType *ASTContext::adjustFunctionType(const FunctionType *T,
return cast<FunctionType>(Result.getTypePtr());
}
+QualType ASTContext::adjustFunctionResultType(QualType FunctionType,
+ QualType ResultType) {
+ // Might be wrapped in a macro qualified type.
+ if (const auto *MQT = dyn_cast<MacroQualifiedType>(FunctionType)) {
+ return getMacroQualifiedType(
+ adjustFunctionResultType(MQT->getUnderlyingType(), ResultType),
+ MQT->getMacroIdentifier());
+ }
+
+ // Might have a calling-convention attribute.
+ if (const auto *AT = dyn_cast<AttributedType>(FunctionType)) {
+ return getAttributedType(
+ AT->getAttrKind(),
+ adjustFunctionResultType(AT->getModifiedType(), ResultType),
+ adjustFunctionResultType(AT->getEquivalentType(), ResultType));
+ }
+
+ // Anything else must be a function type. Rebuild it with the new return value.
+ const auto *FPT = FunctionType->castAs<FunctionProtoType>();
+ return getFunctionType(ResultType, FPT->getParamTypes(),
+ FPT->getExtProtoInfo());
+}
+
void ASTContext::adjustDeducedFunctionResultType(FunctionDecl *FD,
QualType ResultType) {
FD = FD->getMostRecentDecl();
while (true) {
- const auto *FPT = FD->getType()->castAs<FunctionProtoType>();
- FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
- FD->setType(getFunctionType(ResultType, FPT->getParamTypes(), EPI));
+ FD->setType(adjustFunctionResultType(FD->getType(), ResultType));
if (FunctionDecl *Next = FD->getPreviousDecl())
FD = Next;
else
diff --git a/clang/test/SemaCXX/lambda-conversion-op-cc.cpp b/clang/test/SemaCXX/lambda-conversion-op-cc.cpp
index 16ca5535019dff..1a6d197af302fd 100644
--- a/clang/test/SemaCXX/lambda-conversion-op-cc.cpp
+++ b/clang/test/SemaCXX/lambda-conversion-op-cc.cpp
@@ -44,19 +44,19 @@ void useage() {
// CHECK: VarDecl {{.*}} vectorcall '
// CHECK: LambdaExpr
- // CHECK: CXXMethodDecl {{.*}} operator() 'void (int, float, double) __attribute__((vectorcall)) const'
+ // CHECK: CXXMethodDecl {{.*}} operator() 'void (int, float, double) const __attribute__((vectorcall))':'void (int, float, double) __attribute__((vectorcall)) const'
// CHECK: CXXConversionDecl {{.*}} operator void (*)(int, float, double) __attribute__((vectorcall)) 'void
// CHECK: CXXMethodDecl {{.*}} __invoke 'void (int, float, double) __attribute__((vectorcall))' static inline
// WIN32: VarDecl {{.*}} thiscall '
// WIN32: LambdaExpr
- // WIN32: CXXMethodDecl {{.*}} operator() 'void (int, float, double) __attribute__((thiscall)) const'
+ // WIN32: CXXMethodDecl {{.*}} operator() 'void (int, float, double) const __attribute__((thiscall))':'void (int, float, double) __attribute__((thiscall)) const'
// WIN32: CXXConversionDecl {{.*}} operator void (*)(int, float, double) 'void
// WIN32: CXXMethodDecl {{.*}} __invoke 'void (int, float, double)' static inline
// CHECK: VarDecl {{.*}} cdecl '
// CHECK: LambdaExpr
- // CHECK: CXXMethodDecl {{.*}} operator() 'void (int, float, double) const'
+ // CHECK: CXXMethodDecl {{.*}} operator() 'void (int, float, double) const __attribute__((cdecl))':'void (int, float, double) const'
// NODEF: CXXConversionDecl {{.*}} operator void (*)(int, float, double) 'void
// NODEF: CXXMethodDecl {{.*}} __invoke 'void (int, float, double)' static inline
// VECTDEF: CXXConversionDecl {{.*}} operator void (*)(int, float, double) __attribute__((vectorcall)) 'void
@@ -108,8 +108,8 @@ void useage() {
// CHECK: LambdaExpr
// CHECK: FunctionTemplateDecl {{.*}} operator()
// CHECK: CXXMethodDecl {{.*}} operator() 'auto (auto) __attribute__((vectorcall)) const' inline
- // CHECK: CXXMethodDecl {{.*}} operator() 'void (char) __attribute__((vectorcall)) const' implicit_instantiation inline
- // CHECK: CXXMethodDecl {{.*}} operator() 'void (int) __attribute__((vectorcall)) const' implicit_instantiation inline
+ // CHECK: CXXMethodDecl {{.*}} operator() 'void (char) const __attribute__((vectorcall))':'void (char) __attribute__((vectorcall)) const' implicit_instantiation inline
+ // CHECK: CXXMethodDecl {{.*}} operator() 'void (int) const __attribute__((vectorcall))':'void (int) __attribute__((vectorcall)) const' implicit_instantiation inline
// CHECK: FunctionTemplateDecl {{.*}} operator auto (*)(type-parameter-0-0) __attribute__((vectorcall))
// LIN64: CXXConversionDecl {{.*}} operator auto (*)(type-parameter-0-0) __attribute__((vectorcall)) 'auto (*() const noexcept)(auto) __attribute__((vectorcall))'
// LIN64: CXXConversionDecl {{.*}} operator auto (*)(char) __attribute__((vectorcall)) 'void (*() const noexcept)(char) __attribute__((vectorcall))'
>From e5e93bfcaaa077e52499d95a9f2756f1a8bbd223 Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Thu, 14 Mar 2024 22:26:31 +0100
Subject: [PATCH 5/9] [Clang] Add tests for templated lambdas with attributes
---
clang/test/SemaCXX/lambda-attributes.cpp | 53 ++++++++++++++++++++++++
1 file changed, 53 insertions(+)
create mode 100644 clang/test/SemaCXX/lambda-attributes.cpp
diff --git a/clang/test/SemaCXX/lambda-attributes.cpp b/clang/test/SemaCXX/lambda-attributes.cpp
new file mode 100644
index 00000000000000..cca334c0446f87
--- /dev/null
+++ b/clang/test/SemaCXX/lambda-attributes.cpp
@@ -0,0 +1,53 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -ast-dump %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-pc-linux -emit-pch -o %t %s
+// RUN: %clang_cc1 -x c++ -triple x86_64-pc-linux -include-pch %t -ast-dump-all /dev/null | FileCheck %s
+// expected-no-diagnostics
+
+// Check that we both don't crash on transforming FunctionProtoType's
+// wrapped in type sugar and that we don't drop it when performing
+// instantiations either.
+
+#define PRESERVE __attribute__((preserve_most))
+
+// Skip to the instantiation of f().
+// CHECK: FunctionDecl {{.*}} f 'void ()' implicit_instantiation
+template <typename T>
+void f() {
+ // CHECK: CXXMethodDecl {{.*}} operator() 'void (int) const __attribute__((preserve_most))':'void (int) __attribute__((preserve_most)) const' implicit_instantiation
+ (void) [] (T) __attribute__((preserve_most)) { };
+
+ // CHECK: CXXMethodDecl {{.*}} operator() 'void (int) const {{\[}}[clang::annotate_type(...)]]':'void (int) const' implicit_instantiation
+ (void) [] (T) [[clang::annotate_type("foo")]] { };
+
+ // CHECK: CXXMethodDecl {{.*}} operator() 'void (int) const {{\[}}[clang::annotate_type(...)]] {{\[}}[clang::annotate_type(...)]] {{\[}}[clang::annotate_type(...)]]':'void (int) const' implicit_instantiation
+ (void) [] (T) [[clang::annotate_type("foo")]]
+ [[clang::annotate_type("foo")]]
+ [[clang::annotate_type("foo")]] { };
+
+ // CHECK: CXXMethodDecl {{.*}} operator() 'void (int) const __attribute__((preserve_most)) {{\[}}[clang::annotate_type(...)]]':'void (int) __attribute__((preserve_most)) const' implicit_instantiation
+ (void) [] (T) __attribute__((preserve_most))
+ [[clang::annotate_type("foo")]] { };
+
+ // CHECK: CXXMethodDecl {{.*}} operator() 'void (int) const __attribute__((cdecl)) {{\[}}[clang::annotate_type(...)]]':'void (int) const' implicit_instantiation
+ (void) [] (T) __attribute__((cdecl))
+ [[clang::annotate_type("foo")]] { };
+
+ // CHECK: CXXMethodDecl {{.*}} operator() 'void (int) const {{\[}}[clang::annotate_type(...)]]':'void (int) const' implicit_instantiation
+ (void) [] (T t) [[clang::annotate_type("foo", t)]] { };
+
+ // CHECK: CXXMethodDecl {{.*}} operator() 'void (int) const __attribute__((preserve_most)) {{\[}}[clang::annotate_type(...)]]':'void (int) __attribute__((preserve_most)) const' implicit_instantiation
+ (void) [] (T t) __attribute__((preserve_most))
+ [[clang::annotate_type("foo", t, t, t, t)]] { };
+
+ // Check that the MacroQualifiedType is preserved.
+ // CHECK: CXXMethodDecl {{.*}} operator() 'PRESERVE void (int) __attribute__((preserve_most)) const':'void (int) __attribute__((preserve_most)) const' implicit_instantiation
+ (void) [] (T) PRESERVE { };
+
+ // CHECK: CXXMethodDecl {{.*}} operator() 'PRESERVE void (int) __attribute__((preserve_most)) const {{\[}}[clang::annotate_type(...)]]':'void (int) __attribute__((preserve_most)) const' implicit_instantiation
+ (void) [] (T) PRESERVE [[clang::annotate_type("foo")]] { };
+}
+
+void g() {
+ f<int>();
+}
\ No newline at end of file
>From ada50f141d35aceb400971a2be7654623ec0fb5a Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Thu, 14 Mar 2024 22:45:44 +0100
Subject: [PATCH 6/9] [Clang] Add test for nested lambda
---
clang/test/SemaCXX/lambda-attributes.cpp | 17 +++++++++++++----
1 file changed, 13 insertions(+), 4 deletions(-)
diff --git a/clang/test/SemaCXX/lambda-attributes.cpp b/clang/test/SemaCXX/lambda-attributes.cpp
index cca334c0446f87..a7fbed146b3729 100644
--- a/clang/test/SemaCXX/lambda-attributes.cpp
+++ b/clang/test/SemaCXX/lambda-attributes.cpp
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
-// RUN: %clang_cc1 -fsyntax-only -ast-dump %s | FileCheck %s
-// RUN: %clang_cc1 -triple x86_64-pc-linux -emit-pch -o %t %s
-// RUN: %clang_cc1 -x c++ -triple x86_64-pc-linux -include-pch %t -ast-dump-all /dev/null | FileCheck %s
+// RUN: %clang_cc1 -std=c++23 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++23 -fsyntax-only -ast-dump %s | FileCheck %s
+// RUN: %clang_cc1 -std=c++23 -triple x86_64-pc-linux -emit-pch -o %t %s
+// RUN: %clang_cc1 -x c++ -std=c++23 -triple x86_64-pc-linux -include-pch %t -ast-dump-all /dev/null | FileCheck %s
// expected-no-diagnostics
// Check that we both don't crash on transforming FunctionProtoType's
@@ -46,6 +46,15 @@ void f() {
// CHECK: CXXMethodDecl {{.*}} operator() 'PRESERVE void (int) __attribute__((preserve_most)) const {{\[}}[clang::annotate_type(...)]]':'void (int) __attribute__((preserve_most)) const' implicit_instantiation
(void) [] (T) PRESERVE [[clang::annotate_type("foo")]] { };
+
+ // CHECK: CXXMethodDecl {{.*}} operator() 'void (int) const {{\[}}[clang::annotate_type(...)]]':'void (int) const' implicit_instantiation
+ (void) [] (T) [[clang::annotate_type("foo")]] {
+ // CHECK: CXXMethodDecl {{.*}} operator() 'PRESERVE void (int) __attribute__((preserve_most)) const {{\[}}[clang::annotate_type(...)]]':'void (int) __attribute__((preserve_most)) const' implicit_instantiation
+ auto l = []<typename U = T> (U u = {}) PRESERVE [[clang::annotate_type("foo", u)]] { };
+
+ // CHECK: DeclRefExpr {{.*}} 'PRESERVE void (int) __attribute__((preserve_most)) const {{\[}}[clang::annotate_type(...)]]':'void (int) __attribute__((preserve_most)) const' lvalue CXXMethod
+ l();
+ };
}
void g() {
>From 03135c36495c29c5e10b3f0600e2ff75e07fb6a1 Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Thu, 14 Mar 2024 23:17:32 +0100
Subject: [PATCH 7/9] [NFC] clang-format and comment
---
clang/lib/AST/ASTContext.cpp | 3 ++-
clang/lib/Sema/TreeTransform.h | 10 ++--------
clang/test/SemaCXX/lambda-attributes.cpp | 2 +-
3 files changed, 5 insertions(+), 10 deletions(-)
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 16cfae0627d66c..e9f31047c9caef 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -3157,7 +3157,8 @@ QualType ASTContext::adjustFunctionResultType(QualType FunctionType,
adjustFunctionResultType(AT->getEquivalentType(), ResultType));
}
- // Anything else must be a function type. Rebuild it with the new return value.
+ // Anything else must be a function type. Rebuild it with the new return
+ // value.
const auto *FPT = FunctionType->castAs<FunctionProtoType>();
return getFunctionType(ResultType, FPT->getParamTypes(),
FPT->getExtProtoInfo());
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index b129f3db2b7a64..b1a8fd75a90712 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -7208,8 +7208,8 @@ TreeTransform<Derived>::TransformElaboratedType(TypeLocBuilder &TLB,
}
template <typename Derived>
-QualType TreeTransform<Derived>::TransformAttributedType(
- TypeLocBuilder &TLB, AttributedTypeLoc TL) {
+QualType TreeTransform<Derived>::TransformAttributedType(TypeLocBuilder &TLB,
+ AttributedTypeLoc TL) {
const AttributedType *oldType = TL.getTypePtr();
QualType modifiedType = getDerived().TransformType(TLB, TL.getModifiedLoc());
if (modifiedType.isNull())
@@ -7227,12 +7227,6 @@ QualType TreeTransform<Derived>::TransformAttributedType(
if (getDerived().AlwaysRebuild() ||
modifiedType != oldType->getModifiedType()) {
// Do not transform the equivalent type if it is equal to the modified type.
- //
- // This is because, 1. it’s the same type, instantiating it again will yield
- // the same result anyway, and if it doesn't, then that could be a bug in
- // and of itself, and 2. instantiating the same TypeLoc twice is a really
- // bad idea if it's a FunctionProtoType, because instantiating the same
- // ParmVarDecls twice will cause assertion failures.
QualType equivalentType = modifiedType;
if (TL.getModifiedLoc().getType() != TL.getEquivalentTypeLoc().getType()) {
TypeLocBuilder AuxiliaryTLB;
diff --git a/clang/test/SemaCXX/lambda-attributes.cpp b/clang/test/SemaCXX/lambda-attributes.cpp
index a7fbed146b3729..799649719cf42b 100644
--- a/clang/test/SemaCXX/lambda-attributes.cpp
+++ b/clang/test/SemaCXX/lambda-attributes.cpp
@@ -59,4 +59,4 @@ void f() {
void g() {
f<int>();
-}
\ No newline at end of file
+}
>From dbffae3d49be05965b755152c32ae49250404044 Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Fri, 15 Mar 2024 00:31:54 +0100
Subject: [PATCH 8/9] [NFC] Merge declaration and initialisation for some local
variables
---
clang/lib/Sema/TreeTransform.h | 12 ++++--------
1 file changed, 4 insertions(+), 8 deletions(-)
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index b1a8fd75a90712..ae0cc7b4d8acc3 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -13820,18 +13820,14 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
getSema().AddTemplateParametersToLambdaCallOperator(NewCallOperator, Class,
TPL);
- TypeSourceInfo *NewCallOpTSI = nullptr;
- auto OldCallOpTypeLoc =
- E->getCallOperator()->getTypeSourceInfo()->getTypeLoc();
-
- QualType NewCallOpType;
TypeLocBuilder NewCallOpTLBuilder;
-
- NewCallOpType =
+ TypeLoc OldCallOpTypeLoc =
+ E->getCallOperator()->getTypeSourceInfo()->getTypeLoc();
+ QualType NewCallOpType =
getDerived().TransformType(NewCallOpTLBuilder, OldCallOpTypeLoc);
if (NewCallOpType.isNull())
return ExprError();
- NewCallOpTSI =
+ TypeSourceInfo *NewCallOpTSI =
NewCallOpTLBuilder.getTypeSourceInfo(getSema().Context, NewCallOpType);
auto ExtractParams = [](TypeLoc TL) {
>From d6a57b5a5aa123cf38ce3657b764c74c4c5a86f7 Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Fri, 15 Mar 2024 00:55:31 +0100
Subject: [PATCH 9/9] [Clang] Use TypeLoc::getAsAdjusted()
---
clang/lib/Sema/TreeTransform.h | 18 +++++-------------
1 file changed, 5 insertions(+), 13 deletions(-)
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index ae0cc7b4d8acc3..c83e0b009465af 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -13830,18 +13830,10 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
TypeSourceInfo *NewCallOpTSI =
NewCallOpTLBuilder.getTypeSourceInfo(getSema().Context, NewCallOpType);
- auto ExtractParams = [](TypeLoc TL) {
- auto Impl = [](auto Self, TypeLoc TL) -> ArrayRef<ParmVarDecl *> {
- if (auto FPTL = TL.getAs<FunctionProtoTypeLoc>())
- return FPTL.getParams();
- if (auto ATL = TL.getAs<AttributedTypeLoc>())
- return Self(Self, ATL.getModifiedLoc());
- if (auto MQTL = TL.getAs<MacroQualifiedTypeLoc>())
- return Self(Self, MQTL.getInnerLoc());
- llvm_unreachable("Unhandled TypeLoc");
- };
- return Impl(Impl, TL);
- };
+ // The type may be an AttributedType or some other kind of sugar;
+ // get the actual underlying FunctionProtoType.
+ auto FPTL = NewCallOpTSI->getTypeLoc().getAsAdjusted<FunctionProtoTypeLoc>();
+ assert(FPTL && "Not a FunctionProtoType?");
getSema().CompleteLambdaCallOperator(
NewCallOperator, E->getCallOperator()->getLocation(),
@@ -13849,7 +13841,7 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
E->getCallOperator()->getTrailingRequiresClause(), NewCallOpTSI,
E->getCallOperator()->getConstexprKind(),
E->getCallOperator()->getStorageClass(),
- ExtractParams(NewCallOpTSI->getTypeLoc()), E->hasExplicitResultType());
+ FPTL.getParams(), E->hasExplicitResultType());
getDerived().transformAttrs(E->getCallOperator(), NewCallOperator);
getDerived().transformedLocalDecl(E->getCallOperator(), {NewCallOperator});
More information about the cfe-commits
mailing list