[clang] [Clang] Permit noescape on non-pointer types (PR #117344)
Gábor Horváth via cfe-commits
cfe-commits at lists.llvm.org
Mon Dec 2 05:46:28 PST 2024
https://github.com/Xazax-hun updated https://github.com/llvm/llvm-project/pull/117344
>From bd733eec17fdd76a1154d7881f47de2f30b41243 Mon Sep 17 00:00:00 2001
From: Gabor Horvath <gaborh at apple.com>
Date: Fri, 22 Nov 2024 16:19:35 +0000
Subject: [PATCH] [Clang] Permit noescape on non-pointer types
In modern C++ we often use span, string_view or other view objects
instead of raw pointers. This PR opens the door to mark those noescape.
This can be useful to document the API contracts, for interop with
memory safe languages like Swift or Rust, and possibly in the future to
implement take this into account in codegen.
The PR also adds a feature. The goal is to help avoiding warnings when
the code is compiler by earlier versions of clang that does not permit
this attribute on non-pointer types.
---
clang/docs/ReleaseNotes.rst | 2 ++
clang/include/clang/Basic/AttrDocs.td | 12 ++++++------
clang/include/clang/Basic/Features.def | 1 +
clang/lib/Sema/SemaDeclAttr.cpp | 8 --------
clang/test/AST/ast-dump-attr.cpp | 7 ++++++-
clang/test/SemaCXX/noescape-attr.cpp | 9 +++++++--
clang/test/SemaObjCXX/noescape.mm | 6 +++---
7 files changed, 25 insertions(+), 20 deletions(-)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index e73640033f9774..9697395b1d9e4c 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -512,6 +512,8 @@ Attribute Changes in Clang
- The ``target_version`` attribute is now only supported for AArch64 and RISC-V architectures.
+- Now ``__attribute__((noescape))`` can be applied to non-pointer types like ``std::span``.
+
Improvements to Clang's diagnostics
-----------------------------------
diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index 5de39be4805600..096afb3765fe8e 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -228,12 +228,12 @@ members, and static locals.
def NoEscapeDocs : Documentation {
let Category = DocCatVariable;
let Content = [{
-``noescape`` placed on a function parameter of a pointer type is used to inform
-the compiler that the pointer cannot escape: that is, no reference to the object
-the pointer points to that is derived from the parameter value will survive
-after the function returns. Users are responsible for making sure parameters
-annotated with ``noescape`` do not actually escape. Calling ``free()`` on such
-a parameter does not constitute an escape.
+``noescape`` placed on a function parameter is used to inform the compiler that
+the pointer cannot escape: that is, no reference to the object the pointer
+points to that is derived from the parameter value will survive after the
+function returns. Users are responsible for making sure parameters annotated
+with ``noescape`` do not actually escape. Calling ``free()`` on such a
+parameter does not constitute an escape.
For example:
diff --git a/clang/include/clang/Basic/Features.def b/clang/include/clang/Basic/Features.def
index 9088c867d53ce4..5a5cd8f77311cd 100644
--- a/clang/include/clang/Basic/Features.def
+++ b/clang/include/clang/Basic/Features.def
@@ -87,6 +87,7 @@ FEATURE(attribute_overloadable, true)
FEATURE(attribute_unavailable_with_message, true)
FEATURE(attribute_unused_on_fields, true)
FEATURE(attribute_diagnose_if_objc, true)
+FEATURE(attribute_noescape_nonpointer, true)
FEATURE(blocks, LangOpts.Blocks)
FEATURE(c_thread_safety_attributes, true)
FEATURE(cxx_exceptions, LangOpts.CXXExceptions)
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 4fd8ef6dbebf84..e4c7823cb886e0 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -1339,14 +1339,6 @@ static void handleNoEscapeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (D->isInvalidDecl())
return;
- // noescape only applies to pointer types.
- QualType T = cast<ParmVarDecl>(D)->getType();
- if (!S.isValidPointerAttrType(T, /* RefOkay */ true)) {
- S.Diag(AL.getLoc(), diag::warn_attribute_pointers_only)
- << AL << AL.getRange() << 0;
- return;
- }
-
D->addAttr(::new (S.Context) NoEscapeAttr(S.Context, AL));
}
diff --git a/clang/test/AST/ast-dump-attr.cpp b/clang/test/AST/ast-dump-attr.cpp
index f5a74815714218..e6948d82b7efb6 100644
--- a/clang/test/AST/ast-dump-attr.cpp
+++ b/clang/test/AST/ast-dump-attr.cpp
@@ -231,7 +231,12 @@ __attribute__((external_source_symbol(generated_declaration, defined_in="module"
namespace TestNoEscape {
void noescapeFunc(int *p0, __attribute__((noescape)) int *p1) {}
- // CHECK: `-FunctionDecl{{.*}} noescapeFunc 'void (int *, __attribute__((noescape)) int *)'
+ // CHECK: |-FunctionDecl{{.*}} noescapeFunc 'void (int *, __attribute__((noescape)) int *)'
+ // CHECK-NEXT: ParmVarDecl
+ // CHECK-NEXT: ParmVarDecl
+ // CHECK-NEXT: NoEscapeAttr
+ void noescapeFunc2(int *p0, __attribute__((noescape)) int p1) {}
+ // CHECK: `-FunctionDecl{{.*}} noescapeFunc2 'void (int *, __attribute__((noescape)) int)'
// CHECK-NEXT: ParmVarDecl
// CHECK-NEXT: ParmVarDecl
// CHECK-NEXT: NoEscapeAttr
diff --git a/clang/test/SemaCXX/noescape-attr.cpp b/clang/test/SemaCXX/noescape-attr.cpp
index 78dc4f07ffef87..a1ca875eb390a4 100644
--- a/clang/test/SemaCXX/noescape-attr.cpp
+++ b/clang/test/SemaCXX/noescape-attr.cpp
@@ -1,7 +1,12 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
+
template<typename T>
void test1(T __attribute__((noescape)) arr, int size);
-// expected-warning at +1 {{'noescape' attribute only applies to pointer arguments}}
-void test2(int __attribute__((noescape)) arr, int size);
\ No newline at end of file
+void test2(int __attribute__((noescape)) arr, int size);
+
+#if !__has_feature(attribute_noescape_nonpointer)
+ #error "attribute_noescape_nonpointer should be supported"
+#endif
diff --git a/clang/test/SemaObjCXX/noescape.mm b/clang/test/SemaObjCXX/noescape.mm
index 999a91b87300b7..1ce58064fa2fe7 100644
--- a/clang/test/SemaObjCXX/noescape.mm
+++ b/clang/test/SemaObjCXX/noescape.mm
@@ -23,11 +23,11 @@
template <class T>
void noescapeFunc7(__attribute__((noescape)) T &&);
-void invalidFunc0(int __attribute__((noescape))); // expected-warning {{'noescape' attribute only applies to pointer arguments}}
+void invalidFunc0(int __attribute__((noescape)));
void invalidFunc1(int __attribute__((noescape(0)))); // expected-error {{'noescape' attribute takes no arguments}}
void invalidFunc2(int0 *__attribute__((noescape))); // expected-error {{use of undeclared identifier 'int0'; did you mean 'int'?}}
-void invalidFunc3(__attribute__((noescape)) int (S::*Ty)); // expected-warning {{'noescape' attribute only applies to pointer arguments}}
-void invalidFunc4(__attribute__((noescape)) void (S::*Ty)()); // expected-warning {{'noescape' attribute only applies to pointer arguments}}
+void invalidFunc3(__attribute__((noescape)) int (S::*Ty));
+void invalidFunc4(__attribute__((noescape)) void (S::*Ty)());
int __attribute__((noescape)) g; // expected-warning {{'noescape' attribute only applies to parameters}}
struct S1 {
More information about the cfe-commits
mailing list