https://github.com/Sirraide updated https://github.com/llvm/llvm-project/pull/85325
>From 907210a3ad3d829a8e49a5c976d129f8653801bf Mon Sep 17 00:00:00 2001 From: Sirraide <aeternalm...@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 <aeternalm...@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 <aeternalm...@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 <y...@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 <aeternalm...@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 <dwy...@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 <aeternalm...@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 <aeternalm...@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 <aeternalm...@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 <aeternalm...@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 <aeternalm...@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}); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits