Skip to content

[clang] Fix incorrect inferred lifetime_capture_by attr on STL #118013

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Nov 29, 2024

Conversation

hokein
Copy link
Collaborator

@hokein hokein commented Nov 28, 2024

We incorrectly annotate the iterator parameter for insert method (void insert(const_iterator, const value_type& value)), because iterator is also a gsl-pointer type.

This patch fixes it.

We incorrectly annotate the iterator parameter for `insert` method
(`void insert(const_iterator, const value_type& value)`), because
iterator happens to be a gsl-pointer type. This patch fixes it.
@hokein hokein requested a review from usx95 November 28, 2024 14:41
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Nov 28, 2024
@llvmbot
Copy link
Member

llvmbot commented Nov 28, 2024

@llvm/pr-subscribers-clang

Author: Haojian Wu (hokein)

Changes

We incorrectly annotate the iterator parameter for insert method (void insert(const_iterator, const value_type& value)), because iterator is also a gsl-pointer type.

This patch fixes it.


Full diff: https://github.com/llvm/llvm-project/pull/118013.diff

2 Files Affected:

  • (modified) clang/lib/Sema/SemaAttr.cpp (+6-1)
  • (modified) clang/test/AST/attr-lifetime-capture-by.cpp (+28-38)
diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp
index b0849c74e375ed..d3cf42251be2e7 100644
--- a/clang/lib/Sema/SemaAttr.cpp
+++ b/clang/lib/Sema/SemaAttr.cpp
@@ -287,7 +287,12 @@ void Sema::inferLifetimeCaptureByAttribute(FunctionDecl *FD) {
     if (PVD->hasAttr<LifetimeCaptureByAttr>())
       return;
   for (ParmVarDecl *PVD : MD->parameters()) {
-    if (sema::isPointerLikeType(PVD->getType().getNonReferenceType())) {
+    // 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));
diff --git a/clang/test/AST/attr-lifetime-capture-by.cpp b/clang/test/AST/attr-lifetime-capture-by.cpp
index c3afe267301ad7..2a568b0f00d3ae 100644
--- a/clang/test/AST/attr-lifetime-capture-by.cpp
+++ b/clang/test/AST/attr-lifetime-capture-by.cpp
@@ -37,67 +37,56 @@ struct vector {
 struct [[gsl::Pointer()]] View {};
 std::vector<View> views;
 // CHECK:   ClassTemplateSpecializationDecl {{.*}} struct vector definition implicit_instantiation
-// CHECK:       TemplateArgument type 'View'
-// CHECK-NOT:   LifetimeCaptureByAttr
 
 // CHECK:       CXXMethodDecl {{.*}} push_back 'void (const View &)'
-// CHECK:           ParmVarDecl {{.*}} 'const View &'
-// CHECK:               LifetimeCaptureByAttr {{.*}} Implicit
-// CHECK-NOT:   LifetimeCaptureByAttr
+// CHECK-NEXT:           ParmVarDecl {{.*}} 'const View &'
+// CHECK-NEXT:               LifetimeCaptureByAttr {{.*}} Implicit
 
 // CHECK:       CXXMethodDecl {{.*}} push_back 'void (View &&)'
-// CHECK:           ParmVarDecl {{.*}} 'View &&'
-// CHECK:               LifetimeCaptureByAttr {{.*}} Implicit
+// CHECK-NEXT:           ParmVarDecl {{.*}} 'View &&'
+// CHECK-NEXT:               LifetimeCaptureByAttr {{.*}} Implicit
 
 // CHECK:       CXXMethodDecl {{.*}} insert 'void (iterator, View &&)'
-// CHECK:           ParmVarDecl {{.*}} 'iterator'
-// CHECK:               LifetimeCaptureByAttr {{.*}} Implicit
-// CHECK:           ParmVarDecl {{.*}} 'View &&'
-// CHECK:               LifetimeCaptureByAttr {{.*}} Implicit
-// CHECK-NOT:   LifetimeCaptureByAttr
+// CHECK-NEXT:           ParmVarDecl {{.*}} 'iterator'
+// CHECK-NOT:               LifetimeCaptureByAttr {{.*}} Implicit
+// CHECK-NEXT:           ParmVarDecl {{.*}} 'View &&'
+// CHECK-NEXT:               LifetimeCaptureByAttr {{.*}} Implicit
 
 template <class T> struct [[gsl::Pointer()]] ViewTemplate {};
 std::vector<ViewTemplate<int>> templated_views;
-// CHECK:   ClassTemplateSpecializationDecl {{.*}} struct vector definition implicit_instantiation
-// CHECK:       TemplateArgument type 'ViewTemplate<int>'
-// CHECK-NOT:   LifetimeCaptureByAttr
+// CHECK:       ClassTemplateSpecializationDecl {{.*}} struct vector definition implicit_instantiation
 
 // CHECK:       CXXMethodDecl {{.*}} push_back 'void (const ViewTemplate<int> &)'
-// CHECK:           ParmVarDecl {{.*}} 'const ViewTemplate<int> &'
-// CHECK:               LifetimeCaptureByAttr {{.*}} Implicit
+// CHECK-NEXT:           ParmVarDecl {{.*}} 'const ViewTemplate<int> &'
+// CHECK-NEXT:               LifetimeCaptureByAttr {{.*}} Implicit
 // CHECK-NOT:   LifetimeCaptureByAttr
 
 // CHECK:       CXXMethodDecl {{.*}} push_back 'void (ViewTemplate<int> &&)'
-// CHECK:           ParmVarDecl {{.*}} 'ViewTemplate<int> &&'
-// CHECK:               LifetimeCaptureByAttr {{.*}} Implicit
+// CHECK-NEXT:           ParmVarDecl {{.*}} 'ViewTemplate<int> &&'
+// CHECK-NEXT:               LifetimeCaptureByAttr {{.*}} Implicit
 
 // CHECK:       CXXMethodDecl {{.*}} insert 'void (iterator, ViewTemplate<int> &&)'
-// CHECK:           ParmVarDecl {{.*}} 'iterator'
-// CHECK:               LifetimeCaptureByAttr {{.*}} Implicit
-// CHECK:           ParmVarDecl {{.*}} 'ViewTemplate<int> &&'
-// CHECK:               LifetimeCaptureByAttr {{.*}} Implicit
-// CHECK-NOT:   LifetimeCaptureByAttr
+// CHECK-NEXT:           ParmVarDecl {{.*}} 'iterator'
+// CHECK-NOT:               LifetimeCaptureByAttr {{.*}} Implicit
+// CHECK-NEXT:           ParmVarDecl {{.*}} 'ViewTemplate<int> &&'
+// CHECK-NEXT:               LifetimeCaptureByAttr {{.*}} Implicit
 
 std::vector<int*> pointers;
 // CHECK:   ClassTemplateSpecializationDecl {{.*}} struct vector definition implicit_instantiation
-// CHECK:       TemplateArgument type 'int *'
-// CHECK-NOT:   LifetimeCaptureByAttr
 
 // CHECK:       CXXMethodDecl {{.*}} push_back 'void (int *const &)'
-// CHECK:           ParmVarDecl {{.*}} 'int *const &'
-// CHECK:               LifetimeCaptureByAttr {{.*}} Implicit
-// CHECK-NOT:   LifetimeCaptureByAttr
+// CHECK-NEXT:           ParmVarDecl {{.*}} 'int *const &'
+// CHECK-NEXT:               LifetimeCaptureByAttr {{.*}} Implicit
 
 // CHECK:       CXXMethodDecl {{.*}} push_back 'void (int *&&)'
-// CHECK:           ParmVarDecl {{.*}} 'int *&&'
-// CHECK:               LifetimeCaptureByAttr {{.*}} Implicit
+// CHECK-NEXT:           ParmVarDecl {{.*}} 'int *&&'
+// CHECK-NEXT:               LifetimeCaptureByAttr {{.*}} Implicit
 
 // CHECK:       CXXMethodDecl {{.*}} insert 'void (iterator, int *&&)'
-// CHECK:           ParmVarDecl {{.*}} 'iterator'
-// CHECK:               LifetimeCaptureByAttr {{.*}} Implicit
-// CHECK:           ParmVarDecl {{.*}} 'int *&&'
-// CHECK:               LifetimeCaptureByAttr {{.*}} Implicit
-// CHECK-NOT:   LifetimeCaptureByAttr
+// CHECK-NEXT:           ParmVarDecl {{.*}} 'iterator'
+// CHECK-NOT:               LifetimeCaptureByAttr {{.*}} Implicit
+// CHECK-NEXT:           ParmVarDecl {{.*}} 'int *&&'
+// CHECK-NEXT:               LifetimeCaptureByAttr {{.*}} Implicit
 
 std::vector<int> ints;
 // CHECK:   ClassTemplateSpecializationDecl {{.*}} struct vector definition implicit_instantiation
@@ -110,6 +99,7 @@ std::vector<int> ints;
 // CHECK-NOT:   LifetimeCaptureByAttr
 
 // CHECK:       CXXMethodDecl {{.*}} insert 'void (iterator, int &&)'
-// CHECK:           ParmVarDecl {{.*}} 'iterator'
-// CHECK:               LifetimeCaptureByAttr {{.*}} Implicit
+// CHECK-NEXT:           ParmVarDecl {{.*}} 'iterator'
+// CHECK-NOT:               LifetimeCaptureByAttr {{.*}} Implicit
+// CHECK-NEXT:           ParmVarDecl {{.*}} 'int &&'
 // CHECK-NOT:   LifetimeCaptureByAttr

Copy link
Contributor

@usx95 usx95 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you also add a lit test for:

std::vector<std::string> getVector();
std::set<std::string> s;
s.insert(getVector().begin(), getVector().end()); // FIXME: taking iterator of a temporary container without immediate dereference is almost always wrong.

// CHECK: LifetimeCaptureByAttr {{.*}} Implicit
// CHECK-NOT: LifetimeCaptureByAttr
// CHECK-NEXT: ParmVarDecl {{.*}} 'iterator'
// CHECK-NOT: LifetimeCaptureByAttr {{.*}} Implicit
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe skip this line if CHECK-NEXT is possible.
same in line 70, 87

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah, right, this is even better. Done.

@hokein
Copy link
Collaborator Author

hokein commented Nov 29, 2024

Can you also add a lit test for:

std::vector<std::string> getVector();
std::set<std::string> s;
s.insert(getVector().begin(), getVector().end()); // FIXME: taking iterator of a temporary container without immediate dereference is almost always wrong.

I think this is a different issue, I'd prefer not adding it to this test file.

@hokein hokein merged commit 352f868 into llvm:main Nov 29, 2024
5 of 8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants