llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: David Meng (davidmenggx) <details> <summary>Changes</summary> In `const char (&s)[N] [[clang::lifetimebound]]`, the attribute comes after the array brackets, so C++ attaches it to the array type rather than the parameter, and Clang rejected it there. Move it to the parameter instead, which is what `__attribute__((lifetimebound))` in that position already did. Fixes https://github.com/llvm/llvm-project/issues/221221 --- Full diff: https://github.com/llvm/llvm-project/pull/221627.diff 5 Files Affected: - (modified) clang/docs/ReleaseNotes.md (+5) - (modified) clang/lib/Sema/SemaType.cpp (+14-1) - (modified) clang/test/Sema/LifetimeSafety/annotation-suggestions-fixits.cpp (+6) - (modified) clang/test/Sema/attr-lifetimebound.c (+1) - (modified) clang/test/SemaCXX/attr-lifetimebound.cpp (+37) ``````````diff diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index 1686537008499..d0c357281a2e4 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -534,6 +534,11 @@ features cannot lower the translation-unit ABI level; written after the declarator-id, where it appertains to the declared entity rather than to a declarator chunk. (#GH196982, #GH111463) +- `[[clang::lifetimebound]]` is no longer rejected when written after a + parameter's array bound (e.g. `const char (&s)[N] [[clang::lifetimebound]]`); + it now marks the parameter, as `__attribute__((lifetimebound))` already did. + (#GH221221) + #### Bug Fixes to C++ Support - Fixed a false type mismatch when a typedef naming an anonymous enumeration diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 9de4f12aabf68..e54b8516438bb 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -8993,12 +8993,25 @@ static void HandleAnnotateTypeAttr(TypeProcessingState &State, static void HandleLifetimeBoundAttr(TypeProcessingState &State, QualType &CurType, ParsedAttr &Attr) { - if (State.getDeclarator().isDeclarationOfFunction()) { + Declarator &D = State.getDeclarator(); + if (D.isDeclarationOfFunction()) { CurType = State.getAttributedType( createSimpleAttr<LifetimeBoundAttr>(State.getSema().Context, Attr), CurType, CurType); return; } + // An attribute-specifier-seq after an array bound appertains to the array + // type ([dcl.array]p1), so it lands on the array chunk rather than on the + // parameter: + // int *f(const char (&s)[4] [[clang::lifetimebound]]); + // Apply it to the parameter, as the GNU spelling already does. + if (D.isPrototypeContext() && + D.getTypeObject(State.getCurrentChunkIndex()).Kind == + DeclaratorChunk::Array) { + moveAttrFromListToList(Attr, State.getCurrentAttributes(), + D.getAttributes()); + return; + } State.getSema().Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type) << Attr << Attr.isRegularKeywordAttribute() << ExpectedParameterOrImplicitObjectParameter; diff --git a/clang/test/Sema/LifetimeSafety/annotation-suggestions-fixits.cpp b/clang/test/Sema/LifetimeSafety/annotation-suggestions-fixits.cpp index dde1c8f7e2431..839dfcc61e6c8 100644 --- a/clang/test/Sema/LifetimeSafety/annotation-suggestions-fixits.cpp +++ b/clang/test/Sema/LifetimeSafety/annotation-suggestions-fixits.cpp @@ -81,6 +81,12 @@ View param_default(View a = View()) { return a; } +const char *arr_ref_param(const char (&a)[2]) { + // CHECK: :[[@LINE-1]]:45: warning: parameter in intra-TU function should be marked + // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:45-[[@LINE-2]]:45}:" {{\[\[}}clang::lifetimebound]]" + return a; +} + int *arr_default(int a[2] = nullptr) { // CHECK: :[[@LINE-1]]:23: warning: parameter in intra-TU function should be marked // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:23-[[@LINE-2]]:23}:" {{\[\[}}clang::lifetimebound]]" diff --git a/clang/test/Sema/attr-lifetimebound.c b/clang/test/Sema/attr-lifetimebound.c index 6292fe90bdf68..e7ea37f5c9081 100644 --- a/clang/test/Sema/attr-lifetimebound.c +++ b/clang/test/Sema/attr-lifetimebound.c @@ -1,6 +1,7 @@ // RUN: %clang_cc1 -std=c2x -verify %s int *ptr_param(int *param [[clang::lifetimebound]]); +int *array_param(int param[4] [[clang::lifetimebound]]); int *ptr_param_gnu(int *param __attribute__((lifetimebound))); int *ptr_param_redecl(int *param); int *ptr_param_redecl(int *param [[clang::lifetimebound]]); diff --git a/clang/test/SemaCXX/attr-lifetimebound.cpp b/clang/test/SemaCXX/attr-lifetimebound.cpp index 9e2aaff6559c4..74800202a7bb0 100644 --- a/clang/test/SemaCXX/attr-lifetimebound.cpp +++ b/clang/test/SemaCXX/attr-lifetimebound.cpp @@ -28,6 +28,13 @@ namespace usage_invalid { int (*(*func_ptr_ptr)(int) [[clang::lifetimebound]])(int); // expected-error {{'clang::lifetimebound' attribute only applies to parameters and implicit object parameters}} struct X {}; int (X::*member_func_ptr)(int) [[clang::lifetimebound]]; // expected-error {{'clang::lifetimebound' attribute only applies to parameters and implicit object parameters}} + + int attr_on_array_var[4] [[clang::lifetimebound]]; // expected-error {{'clang::lifetimebound' attribute only applies to parameters and implicit object parameters}} + void attr_on_array_param_void_return(int (¶m)[4] [[clang::lifetimebound]]); // expected-error {{'lifetimebound' attribute cannot be applied to a parameter of a function that returns void; did you mean 'lifetime_capture_by(X)'}} + int *attr_on_array_param_with_args(int (¶m)[4] [[clang::lifetimebound(42)]]); // expected-error {{takes no arguments}} + using attr_on_array_alias = int[4] [[clang::lifetimebound]]; // expected-error {{'clang::lifetimebound' attribute only applies to parameters and implicit object parameters}} + static_assert(sizeof(int[4] [[clang::lifetimebound]]) > 0); // expected-error {{'clang::lifetimebound' attribute only applies to parameters and implicit object parameters}} \ + // expected-warning {{'clang::lifetimebound' attribute ignored when parsing type}} } namespace usage_ok { @@ -383,3 +390,33 @@ void test(StatusOr<FooView> foo1, StatusOr<NonAnnotatedFooView> foo2) { foo2 = NonAnnotatedFoo(); // expected-warning {{object backing 'foo2' will be destroyed at the end}} } } // namespace GH106372 + +namespace array_params { + // An attribute written after an array bound is applied to the parameter. + const char *ref_to_array(const char (&a)[4] [[clang::lifetimebound]]) { return a; } + int *decayed_array(int a[4] [[clang::lifetimebound]]); + int *ptr_to_array(int (*a)[4] [[clang::lifetimebound]]); + template <int N> const char *dependent_ref_to_array(const char (&a)[N] [[clang::lifetimebound]]); + const char *gnu_ref_to_array(const char (&a)[4] __attribute__((lifetimebound))); + + const char *test_ref_to_array() { + char a[4]; + return ref_to_array(a); // expected-warning {{address of stack memory associated with local variable 'a' returned}} + } + int *test_decayed_array() { + int a[4]; + return decayed_array(a); // expected-warning {{address of stack memory associated with local variable 'a' returned}} + } + int *test_ptr_to_array() { + int a[4]; + return ptr_to_array(&a); // expected-warning {{address of stack memory associated with local variable 'a' returned}} + } + const char *test_dependent_ref_to_array() { + char a[4]; + return dependent_ref_to_array(a); // expected-warning {{address of stack memory associated with local variable 'a' returned}} + } + const char *test_gnu_ref_to_array() { + char a[4]; + return gnu_ref_to_array(a); // expected-warning {{address of stack memory associated with local variable 'a' returned}} + } +} // namespace array_params `````````` </details> https://github.com/llvm/llvm-project/pull/221627 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
