[clang] [clang] Infer lifetime_capture_by for map's subscript operator. (PR #118078)
https://github.com/hokein closed https://github.com/llvm/llvm-project/pull/118078 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Infer lifetime_capture_by for map's subscript operator. (PR #118078)
@@ -270,34 +270,49 @@ void Sema::inferLifetimeBoundAttribute(FunctionDecl *FD) { } void Sema::inferLifetimeCaptureByAttribute(FunctionDecl *FD) { - if (!FD) + auto *MD = dyn_cast_if_present(FD); + if (!MD || !MD->getParent()->isInStdNamespace()) return; - auto *MD = dyn_cast(FD); - if (!MD || !MD->getIdentifier() || !MD->getParent()->isInStdNamespace()) + auto Annotate = [this](const FunctionDecl *MD) { +// Do not infer if any parameter is explicitly annotated. +for (ParmVarDecl *PVD : MD->parameters()) + if (PVD->hasAttr()) +return; +for (ParmVarDecl *PVD : MD->parameters()) { + // Methods in standard containers that capture values typically accept + // reference-type parameters, e.g., `void push_back(const T& value)`. + // We only apply the lifetime_capture_by attribute to parameters of + // pointer-like reference types (`const T&`, `T&&`). + if (PVD->getType()->isReferenceType() && + sema::isPointerLikeType(PVD->getType().getNonReferenceType())) { +int CaptureByThis[] = {LifetimeCaptureByAttr::THIS}; +PVD->addAttr( +LifetimeCaptureByAttr::CreateImplicit(Context, CaptureByThis, 1)); + } +} + }; + + if (!MD->getIdentifier()) { +static const llvm::StringSet<> MapLikeContainer{ +"map", +"multimap", +"unordered_map", +"unordered_multimap", +}; +// Infer for the map's operator []: +//std::map m; +//m[ReturnString(..)] = ...; // !dangling references in m. +if (MD->getOverloadedOperator() != OO_Subscript || +!MapLikeContainer.contains(MD->getParent()->getName())) + return; hokein wrote: Done. https://github.com/llvm/llvm-project/pull/118078 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Infer lifetime_capture_by for map's subscript operator. (PR #118078)
https://github.com/hokein updated https://github.com/llvm/llvm-project/pull/118078 >From 4db8f43507d6d36ef1cfeabb4c308e781a1b061e Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Fri, 29 Nov 2024 11:07:56 +0100 Subject: [PATCH 1/2] [clang] Infer lifetime_capture_by for map's subscript operator. --- clang/lib/Sema/SemaAttr.cpp | 59 + clang/test/AST/attr-lifetime-capture-by.cpp | 16 ++ 2 files changed, 53 insertions(+), 22 deletions(-) diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp index d3cf42251be2e7..3279f4109a9c02 100644 --- a/clang/lib/Sema/SemaAttr.cpp +++ b/clang/lib/Sema/SemaAttr.cpp @@ -270,34 +270,49 @@ void Sema::inferLifetimeBoundAttribute(FunctionDecl *FD) { } void Sema::inferLifetimeCaptureByAttribute(FunctionDecl *FD) { - if (!FD) + auto *MD = dyn_cast_if_present(FD); + if (!MD || !MD->getParent()->isInStdNamespace()) return; - auto *MD = dyn_cast(FD); - if (!MD || !MD->getIdentifier() || !MD->getParent()->isInStdNamespace()) + auto Annotate = [this](const FunctionDecl *MD) { +// Do not infer if any parameter is explicitly annotated. +for (ParmVarDecl *PVD : MD->parameters()) + if (PVD->hasAttr()) +return; +for (ParmVarDecl *PVD : MD->parameters()) { + // Methods in standard containers that capture values typically accept + // reference-type parameters, e.g., `void push_back(const T& value)`. + // We only apply the lifetime_capture_by attribute to parameters of + // pointer-like reference types (`const T&`, `T&&`). + if (PVD->getType()->isReferenceType() && + sema::isPointerLikeType(PVD->getType().getNonReferenceType())) { +int CaptureByThis[] = {LifetimeCaptureByAttr::THIS}; +PVD->addAttr( +LifetimeCaptureByAttr::CreateImplicit(Context, CaptureByThis, 1)); + } +} + }; + + if (!MD->getIdentifier()) { +static const llvm::StringSet<> MapLikeContainer{ +"map", +"multimap", +"unordered_map", +"unordered_multimap", +}; +// Infer for the map's operator []: +//std::map m; +//m[ReturnString(..)] = ...; // !dangling references in m. +if (MD->getOverloadedOperator() != OO_Subscript || +!MapLikeContainer.contains(MD->getParent()->getName())) + return; +Annotate(MD); return; - // FIXME: Infer for operator[] for map-like containers. For example: - //std::map m; - //m[ReturnString(..)] = ...; + } static const llvm::StringSet<> CapturingMethods{"insert", "push", "push_front", "push_back"}; if (!CapturingMethods.contains(MD->getName())) return; - // Do not infer if any parameter is explicitly annotated. - for (ParmVarDecl *PVD : MD->parameters()) -if (PVD->hasAttr()) - return; - for (ParmVarDecl *PVD : MD->parameters()) { -// Methods in standard containers that capture values typically accept -// reference-type parameters, e.g., `void push_back(const T& value)`. -// We only apply the lifetime_capture_by attribute to parameters of -// pointer-like reference types (`const T&`, `T&&`). -if (PVD->getType()->isReferenceType() && -sema::isPointerLikeType(PVD->getType().getNonReferenceType())) { - int CaptureByThis[] = {LifetimeCaptureByAttr::THIS}; - PVD->addAttr( - LifetimeCaptureByAttr::CreateImplicit(Context, CaptureByThis, 1)); -} - } + Annotate(MD); } void Sema::inferNullableClassAttribute(CXXRecordDecl *CRD) { diff --git a/clang/test/AST/attr-lifetime-capture-by.cpp b/clang/test/AST/attr-lifetime-capture-by.cpp index debad9b7204d72..71b348dac764bc 100644 --- a/clang/test/AST/attr-lifetime-capture-by.cpp +++ b/clang/test/AST/attr-lifetime-capture-by.cpp @@ -30,6 +30,12 @@ struct vector { void insert(iterator, T&&); }; + +template +struct map { + Value& operator[](Key&& p); + Value& operator[](const Key& p); +}; } // namespace std // CHECK-NOT: LifetimeCaptureByAttr @@ -99,3 +105,13 @@ std::vector ints; // CHECK-NEXT: ParmVarDecl {{.*}} 'iterator' // CHECK-NEXT: ParmVarDecl {{.*}} 'int &&' // CHECK-NOT: LifetimeCaptureByAttr + +std::map map; +// CHECK: ClassTemplateSpecializationDecl {{.*}} struct map definition implicit_instantiation + +// CHECK: CXXMethodDecl {{.*}} operator[] 'int &(View &&)' implicit_instantiation +// CHECK-NEXT: ParmVarDecl {{.*}} p 'View &&' +// CHECK-NEXT: LifetimeCaptureByAttr {{.*}} Implicit +// CHECK: CXXMethodDecl {{.*}} operator[] 'int &(const View &)' implicit_instantiation +// CHECK-NEXT: ParmVarDecl {{.*}} p 'const View &' +// CHECK-NEXT: LifetimeCaptureByAttr {{.*}} Implicit >From ce01d4b7566ce7d0a098155a71ac8b8ae40a7a7b Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Mon, 2 Dec 2024 09:24:41 +0100 Subject: [PATCH 2/2] Address review comment. --- clang/lib/Sema/Se
[clang] [clang] Infer lifetime_capture_by for map's subscript operator. (PR #118078)
@@ -270,34 +270,49 @@ void Sema::inferLifetimeBoundAttribute(FunctionDecl *FD) { } void Sema::inferLifetimeCaptureByAttribute(FunctionDecl *FD) { - if (!FD) + auto *MD = dyn_cast_if_present(FD); + if (!MD || !MD->getParent()->isInStdNamespace()) return; - auto *MD = dyn_cast(FD); - if (!MD || !MD->getIdentifier() || !MD->getParent()->isInStdNamespace()) + auto Annotate = [this](const FunctionDecl *MD) { +// Do not infer if any parameter is explicitly annotated. +for (ParmVarDecl *PVD : MD->parameters()) + if (PVD->hasAttr()) +return; +for (ParmVarDecl *PVD : MD->parameters()) { + // Methods in standard containers that capture values typically accept + // reference-type parameters, e.g., `void push_back(const T& value)`. + // We only apply the lifetime_capture_by attribute to parameters of + // pointer-like reference types (`const T&`, `T&&`). + if (PVD->getType()->isReferenceType() && + sema::isPointerLikeType(PVD->getType().getNonReferenceType())) { +int CaptureByThis[] = {LifetimeCaptureByAttr::THIS}; +PVD->addAttr( +LifetimeCaptureByAttr::CreateImplicit(Context, CaptureByThis, 1)); + } +} + }; + + if (!MD->getIdentifier()) { +static const llvm::StringSet<> MapLikeContainer{ +"map", +"multimap", +"unordered_map", +"unordered_multimap", +}; +// Infer for the map's operator []: +//std::map m; +//m[ReturnString(..)] = ...; // !dangling references in m. +if (MD->getOverloadedOperator() != OO_Subscript || +!MapLikeContainer.contains(MD->getParent()->getName())) + return; usx95 wrote: nit: early returns complicates this. Maybe simplify like: ```cpp if (MD->getOverloadedOperator() == OO_Subscript && MapLikeContainer.contains(MD->getParent()->getName())) Annotate(MD); return; ``` https://github.com/llvm/llvm-project/pull/118078 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Infer lifetime_capture_by for map's subscript operator. (PR #118078)
https://github.com/usx95 approved this pull request. Thanks. LGTM. https://github.com/llvm/llvm-project/pull/118078 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Infer lifetime_capture_by for map's subscript operator. (PR #118078)
https://github.com/usx95 edited https://github.com/llvm/llvm-project/pull/118078 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Infer lifetime_capture_by for map's subscript operator. (PR #118078)
llvmbot wrote: @llvm/pr-subscribers-clang Author: Haojian Wu (hokein) Changes --- Full diff: https://github.com/llvm/llvm-project/pull/118078.diff 2 Files Affected: - (modified) clang/lib/Sema/SemaAttr.cpp (+37-22) - (modified) clang/test/AST/attr-lifetime-capture-by.cpp (+16) ``diff diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp index d3cf42251be2e7..3279f4109a9c02 100644 --- a/clang/lib/Sema/SemaAttr.cpp +++ b/clang/lib/Sema/SemaAttr.cpp @@ -270,34 +270,49 @@ void Sema::inferLifetimeBoundAttribute(FunctionDecl *FD) { } void Sema::inferLifetimeCaptureByAttribute(FunctionDecl *FD) { - if (!FD) + auto *MD = dyn_cast_if_present(FD); + if (!MD || !MD->getParent()->isInStdNamespace()) return; - auto *MD = dyn_cast(FD); - if (!MD || !MD->getIdentifier() || !MD->getParent()->isInStdNamespace()) + auto Annotate = [this](const FunctionDecl *MD) { +// Do not infer if any parameter is explicitly annotated. +for (ParmVarDecl *PVD : MD->parameters()) + if (PVD->hasAttr()) +return; +for (ParmVarDecl *PVD : MD->parameters()) { + // Methods in standard containers that capture values typically accept + // reference-type parameters, e.g., `void push_back(const T& value)`. + // We only apply the lifetime_capture_by attribute to parameters of + // pointer-like reference types (`const T&`, `T&&`). + if (PVD->getType()->isReferenceType() && + sema::isPointerLikeType(PVD->getType().getNonReferenceType())) { +int CaptureByThis[] = {LifetimeCaptureByAttr::THIS}; +PVD->addAttr( +LifetimeCaptureByAttr::CreateImplicit(Context, CaptureByThis, 1)); + } +} + }; + + if (!MD->getIdentifier()) { +static const llvm::StringSet<> MapLikeContainer{ +"map", +"multimap", +"unordered_map", +"unordered_multimap", +}; +// Infer for the map's operator []: +//std::map m; +//m[ReturnString(..)] = ...; // !dangling references in m. +if (MD->getOverloadedOperator() != OO_Subscript || +!MapLikeContainer.contains(MD->getParent()->getName())) + return; +Annotate(MD); return; - // FIXME: Infer for operator[] for map-like containers. For example: - //std::map m; - //m[ReturnString(..)] = ...; + } static const llvm::StringSet<> CapturingMethods{"insert", "push", "push_front", "push_back"}; if (!CapturingMethods.contains(MD->getName())) return; - // Do not infer if any parameter is explicitly annotated. - for (ParmVarDecl *PVD : MD->parameters()) -if (PVD->hasAttr()) - return; - for (ParmVarDecl *PVD : MD->parameters()) { -// Methods in standard containers that capture values typically accept -// reference-type parameters, e.g., `void push_back(const T& value)`. -// We only apply the lifetime_capture_by attribute to parameters of -// pointer-like reference types (`const T&`, `T&&`). -if (PVD->getType()->isReferenceType() && -sema::isPointerLikeType(PVD->getType().getNonReferenceType())) { - int CaptureByThis[] = {LifetimeCaptureByAttr::THIS}; - PVD->addAttr( - LifetimeCaptureByAttr::CreateImplicit(Context, CaptureByThis, 1)); -} - } + Annotate(MD); } void Sema::inferNullableClassAttribute(CXXRecordDecl *CRD) { diff --git a/clang/test/AST/attr-lifetime-capture-by.cpp b/clang/test/AST/attr-lifetime-capture-by.cpp index debad9b7204d72..71b348dac764bc 100644 --- a/clang/test/AST/attr-lifetime-capture-by.cpp +++ b/clang/test/AST/attr-lifetime-capture-by.cpp @@ -30,6 +30,12 @@ struct vector { void insert(iterator, T&&); }; + +template +struct map { + Value& operator[](Key&& p); + Value& operator[](const Key& p); +}; } // namespace std // CHECK-NOT: LifetimeCaptureByAttr @@ -99,3 +105,13 @@ std::vector ints; // CHECK-NEXT: ParmVarDecl {{.*}} 'iterator' // CHECK-NEXT: ParmVarDecl {{.*}} 'int &&' // CHECK-NOT: LifetimeCaptureByAttr + +std::map map; +// CHECK: ClassTemplateSpecializationDecl {{.*}} struct map definition implicit_instantiation + +// CHECK: CXXMethodDecl {{.*}} operator[] 'int &(View &&)' implicit_instantiation +// CHECK-NEXT: ParmVarDecl {{.*}} p 'View &&' +// CHECK-NEXT: LifetimeCaptureByAttr {{.*}} Implicit +// CHECK: CXXMethodDecl {{.*}} operator[] 'int &(const View &)' implicit_instantiation +// CHECK-NEXT: ParmVarDecl {{.*}} p 'const View &' +// CHECK-NEXT: LifetimeCaptureByAttr {{.*}} Implicit `` https://github.com/llvm/llvm-project/pull/118078 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [clang] Infer lifetime_capture_by for map's subscript operator. (PR #118078)
https://github.com/hokein created https://github.com/llvm/llvm-project/pull/118078 None >From 18d56e847901653de9f84e256f30ec0e16ebca96 Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Fri, 29 Nov 2024 11:07:56 +0100 Subject: [PATCH] [clang] Infer lifetime_capture_by for map's subscript operator. --- clang/lib/Sema/SemaAttr.cpp | 59 + clang/test/AST/attr-lifetime-capture-by.cpp | 16 ++ 2 files changed, 53 insertions(+), 22 deletions(-) diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp index d3cf42251be2e7..3279f4109a9c02 100644 --- a/clang/lib/Sema/SemaAttr.cpp +++ b/clang/lib/Sema/SemaAttr.cpp @@ -270,34 +270,49 @@ void Sema::inferLifetimeBoundAttribute(FunctionDecl *FD) { } void Sema::inferLifetimeCaptureByAttribute(FunctionDecl *FD) { - if (!FD) + auto *MD = dyn_cast_if_present(FD); + if (!MD || !MD->getParent()->isInStdNamespace()) return; - auto *MD = dyn_cast(FD); - if (!MD || !MD->getIdentifier() || !MD->getParent()->isInStdNamespace()) + auto Annotate = [this](const FunctionDecl *MD) { +// Do not infer if any parameter is explicitly annotated. +for (ParmVarDecl *PVD : MD->parameters()) + if (PVD->hasAttr()) +return; +for (ParmVarDecl *PVD : MD->parameters()) { + // Methods in standard containers that capture values typically accept + // reference-type parameters, e.g., `void push_back(const T& value)`. + // We only apply the lifetime_capture_by attribute to parameters of + // pointer-like reference types (`const T&`, `T&&`). + if (PVD->getType()->isReferenceType() && + sema::isPointerLikeType(PVD->getType().getNonReferenceType())) { +int CaptureByThis[] = {LifetimeCaptureByAttr::THIS}; +PVD->addAttr( +LifetimeCaptureByAttr::CreateImplicit(Context, CaptureByThis, 1)); + } +} + }; + + if (!MD->getIdentifier()) { +static const llvm::StringSet<> MapLikeContainer{ +"map", +"multimap", +"unordered_map", +"unordered_multimap", +}; +// Infer for the map's operator []: +//std::map m; +//m[ReturnString(..)] = ...; // !dangling references in m. +if (MD->getOverloadedOperator() != OO_Subscript || +!MapLikeContainer.contains(MD->getParent()->getName())) + return; +Annotate(MD); return; - // FIXME: Infer for operator[] for map-like containers. For example: - //std::map m; - //m[ReturnString(..)] = ...; + } static const llvm::StringSet<> CapturingMethods{"insert", "push", "push_front", "push_back"}; if (!CapturingMethods.contains(MD->getName())) return; - // Do not infer if any parameter is explicitly annotated. - for (ParmVarDecl *PVD : MD->parameters()) -if (PVD->hasAttr()) - return; - for (ParmVarDecl *PVD : MD->parameters()) { -// Methods in standard containers that capture values typically accept -// reference-type parameters, e.g., `void push_back(const T& value)`. -// We only apply the lifetime_capture_by attribute to parameters of -// pointer-like reference types (`const T&`, `T&&`). -if (PVD->getType()->isReferenceType() && -sema::isPointerLikeType(PVD->getType().getNonReferenceType())) { - int CaptureByThis[] = {LifetimeCaptureByAttr::THIS}; - PVD->addAttr( - LifetimeCaptureByAttr::CreateImplicit(Context, CaptureByThis, 1)); -} - } + Annotate(MD); } void Sema::inferNullableClassAttribute(CXXRecordDecl *CRD) { diff --git a/clang/test/AST/attr-lifetime-capture-by.cpp b/clang/test/AST/attr-lifetime-capture-by.cpp index debad9b7204d72..71b348dac764bc 100644 --- a/clang/test/AST/attr-lifetime-capture-by.cpp +++ b/clang/test/AST/attr-lifetime-capture-by.cpp @@ -30,6 +30,12 @@ struct vector { void insert(iterator, T&&); }; + +template +struct map { + Value& operator[](Key&& p); + Value& operator[](const Key& p); +}; } // namespace std // CHECK-NOT: LifetimeCaptureByAttr @@ -99,3 +105,13 @@ std::vector ints; // CHECK-NEXT: ParmVarDecl {{.*}} 'iterator' // CHECK-NEXT: ParmVarDecl {{.*}} 'int &&' // CHECK-NOT: LifetimeCaptureByAttr + +std::map map; +// CHECK: ClassTemplateSpecializationDecl {{.*}} struct map definition implicit_instantiation + +// CHECK: CXXMethodDecl {{.*}} operator[] 'int &(View &&)' implicit_instantiation +// CHECK-NEXT: ParmVarDecl {{.*}} p 'View &&' +// CHECK-NEXT: LifetimeCaptureByAttr {{.*}} Implicit +// CHECK: CXXMethodDecl {{.*}} operator[] 'int &(const View &)' implicit_instantiation +// CHECK-NEXT: ParmVarDecl {{.*}} p 'const View &' +// CHECK-NEXT: LifetimeCaptureByAttr {{.*}} Implicit ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits