Skip to content

Commit bd733ee

Browse files
author
Gabor Horvath
committed
[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.
1 parent c1dcf75 commit bd733ee

File tree

7 files changed

+25
-20
lines changed

7 files changed

+25
-20
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,8 @@ Attribute Changes in Clang
512512

513513
- The ``target_version`` attribute is now only supported for AArch64 and RISC-V architectures.
514514

515+
- Now ``__attribute__((noescape))`` can be applied to non-pointer types like ``std::span``.
516+
515517
Improvements to Clang's diagnostics
516518
-----------------------------------
517519

clang/include/clang/Basic/AttrDocs.td

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -228,12 +228,12 @@ members, and static locals.
228228
def NoEscapeDocs : Documentation {
229229
let Category = DocCatVariable;
230230
let Content = [{
231-
``noescape`` placed on a function parameter of a pointer type is used to inform
232-
the compiler that the pointer cannot escape: that is, no reference to the object
233-
the pointer points to that is derived from the parameter value will survive
234-
after the function returns. Users are responsible for making sure parameters
235-
annotated with ``noescape`` do not actually escape. Calling ``free()`` on such
236-
a parameter does not constitute an escape.
231+
``noescape`` placed on a function parameter is used to inform the compiler that
232+
the pointer cannot escape: that is, no reference to the object the pointer
233+
points to that is derived from the parameter value will survive after the
234+
function returns. Users are responsible for making sure parameters annotated
235+
with ``noescape`` do not actually escape. Calling ``free()`` on such a
236+
parameter does not constitute an escape.
237237

238238
For example:
239239

clang/include/clang/Basic/Features.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ FEATURE(attribute_overloadable, true)
8787
FEATURE(attribute_unavailable_with_message, true)
8888
FEATURE(attribute_unused_on_fields, true)
8989
FEATURE(attribute_diagnose_if_objc, true)
90+
FEATURE(attribute_noescape_nonpointer, true)
9091
FEATURE(blocks, LangOpts.Blocks)
9192
FEATURE(c_thread_safety_attributes, true)
9293
FEATURE(cxx_exceptions, LangOpts.CXXExceptions)

clang/lib/Sema/SemaDeclAttr.cpp

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1339,14 +1339,6 @@ static void handleNoEscapeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
13391339
if (D->isInvalidDecl())
13401340
return;
13411341

1342-
// noescape only applies to pointer types.
1343-
QualType T = cast<ParmVarDecl>(D)->getType();
1344-
if (!S.isValidPointerAttrType(T, /* RefOkay */ true)) {
1345-
S.Diag(AL.getLoc(), diag::warn_attribute_pointers_only)
1346-
<< AL << AL.getRange() << 0;
1347-
return;
1348-
}
1349-
13501342
D->addAttr(::new (S.Context) NoEscapeAttr(S.Context, AL));
13511343
}
13521344

clang/test/AST/ast-dump-attr.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,12 @@ __attribute__((external_source_symbol(generated_declaration, defined_in="module"
231231

232232
namespace TestNoEscape {
233233
void noescapeFunc(int *p0, __attribute__((noescape)) int *p1) {}
234-
// CHECK: `-FunctionDecl{{.*}} noescapeFunc 'void (int *, __attribute__((noescape)) int *)'
234+
// CHECK: |-FunctionDecl{{.*}} noescapeFunc 'void (int *, __attribute__((noescape)) int *)'
235+
// CHECK-NEXT: ParmVarDecl
236+
// CHECK-NEXT: ParmVarDecl
237+
// CHECK-NEXT: NoEscapeAttr
238+
void noescapeFunc2(int *p0, __attribute__((noescape)) int p1) {}
239+
// CHECK: `-FunctionDecl{{.*}} noescapeFunc2 'void (int *, __attribute__((noescape)) int)'
235240
// CHECK-NEXT: ParmVarDecl
236241
// CHECK-NEXT: ParmVarDecl
237242
// CHECK-NEXT: NoEscapeAttr

clang/test/SemaCXX/noescape-attr.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
// RUN: %clang_cc1 -fsyntax-only -verify %s
22

3+
// expected-no-diagnostics
4+
35
template<typename T>
46
void test1(T __attribute__((noescape)) arr, int size);
57

6-
// expected-warning@+1 {{'noescape' attribute only applies to pointer arguments}}
7-
void test2(int __attribute__((noescape)) arr, int size);
8+
void test2(int __attribute__((noescape)) arr, int size);
9+
10+
#if !__has_feature(attribute_noescape_nonpointer)
11+
#error "attribute_noescape_nonpointer should be supported"
12+
#endif

clang/test/SemaObjCXX/noescape.mm

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,11 @@
2323
template <class T>
2424
void noescapeFunc7(__attribute__((noescape)) T &&);
2525

26-
void invalidFunc0(int __attribute__((noescape))); // expected-warning {{'noescape' attribute only applies to pointer arguments}}
26+
void invalidFunc0(int __attribute__((noescape)));
2727
void invalidFunc1(int __attribute__((noescape(0)))); // expected-error {{'noescape' attribute takes no arguments}}
2828
void invalidFunc2(int0 *__attribute__((noescape))); // expected-error {{use of undeclared identifier 'int0'; did you mean 'int'?}}
29-
void invalidFunc3(__attribute__((noescape)) int (S::*Ty)); // expected-warning {{'noescape' attribute only applies to pointer arguments}}
30-
void invalidFunc4(__attribute__((noescape)) void (S::*Ty)()); // expected-warning {{'noescape' attribute only applies to pointer arguments}}
29+
void invalidFunc3(__attribute__((noescape)) int (S::*Ty));
30+
void invalidFunc4(__attribute__((noescape)) void (S::*Ty)());
3131
int __attribute__((noescape)) g; // expected-warning {{'noescape' attribute only applies to parameters}}
3232

3333
struct S1 {

0 commit comments

Comments
 (0)