[PATCH] D32210: [Sema][ObjC] Add support for attribute "noescape"
Aaron Ballman via Phabricator via cfe-commits
cfe-commits at lists.llvm.org
Wed Apr 19 07:22:14 PDT 2017
aaron.ballman added inline comments.
================
Comment at: include/clang/Basic/Attr.td:1222
+def NoEscape : InheritableAttr {
+ let Spellings = [GCC<"noescape">, CXX11<"clang", "noescape">];
+ let Subjects = SubjectList<[ParmVar], WarnDiag, "ExpectedParameter">;
----------------
I do not think GCC supports this attribute, so that should be using a GNU spelling rather than a GCC spelling.
================
Comment at: include/clang/Basic/Attr.td:1223
+ let Spellings = [GCC<"noescape">, CXX11<"clang", "noescape">];
+ let Subjects = SubjectList<[ParmVar], WarnDiag, "ExpectedParameter">;
+ let Documentation = [NoEscapeDocs];
----------------
No need to specify the last two arguments, they should be handled by default already.
================
Comment at: include/clang/Basic/AttrDocs.td:118
+ let Content = [{
+``noescape`` placed on a block parameter is used to inform the compiler that the block passed to a function cannot escape: that is, the block will not be invoked after the function returns. To ensure that the block does not escape, clang imposes the following restrictions on usage of non-escaping blocks:
+
----------------
Please wrap to 80 columns.
"block parameter" is a bit strange -- I assumed that meant parameter to a block, not a function parameter of block type. May want to clarify.
Should also clarify "the block will not be invoked after the function returns." Does this code produce undefined behavior?
```
typedef void (^BlockTy)();
void nonescapingFunc(__attribute__((noescape)) BlockTy);
void escapingFunc(BlockTy);
void callerFunc(__attribute__((noescape)) BlockTy block) {
nonescapingFunc(block); // OK
escapingFunc(block); // error: parameter is not annotated with noescape
}
void f(void) {
BlockTy Blk = ^{};
callerFunc(Blk);
Blk();
}
```
================
Comment at: include/clang/Basic/DiagnosticSemaKinds.td:3094
+def err_noescape_passed_to_call : Error<
+ "cannot pass non-escaping parameter '%0' to function or method expecting escaping "
+ "argument">;
----------------
expecting an escaping argument
Also, someday we should make non-foo vs nonfoo a consistent decision in our diagnostics. We seem to use both forms.
================
Comment at: include/clang/Basic/DiagnosticSemaKinds.td:3106
+def note_noescape_parameter : Note<
+ "parameter is %select{annotated|not annotated}0 with noescape">;
+
----------------
Should quote `noescape`.
================
Comment at: lib/Sema/SemaChecking.cpp:2545
+ SourceLocation CallSiteLoc) {
+ ArrayRef<ParmVarDecl*> Params = FDecl->parameters();
+
----------------
Space before the asterisk.
================
Comment at: lib/Sema/SemaChecking.cpp:2548
+ for (unsigned I = 0, E = Args.size(); I < E ; ++I) {
+ const auto *CalleePD = I < Params.size() ? Params[I] : nullptr;
+
----------------
Please don't use `auto` here.
================
Comment at: lib/Sema/SemaChecking.cpp:2559
+ if (const auto *DRE = dyn_cast<DeclRefExpr>(Args[I]->IgnoreImpCasts())) {
+ const auto *CallerPD = DRE->getDecl();
+ if (CallerPD->hasAttr<NoEscapeAttr>()) {
----------------
Don't use `auto` here.
================
Comment at: lib/Sema/SemaChecking.cpp:2562
+ S.Diag(Args[I]->getExprLoc(), diag::err_noescape_passed_to_call)
+ << CallerPD->getName();
+ S.Diag(CallerPD->getLocation(), diag::note_noescape_parameter) << 0;
----------------
No need to use `getName()` here, you can just pass in the declaration directly. That means you should also remove the quotes from the diagnostic so it does not get double-quoted.
================
Comment at: lib/Sema/SemaChecking.cpp:2567
+ else
+ assert(FDecl->isVariadic() &&
+ "Called function expected to be variadic");
----------------
What about functions that have no prototype (they're not variadic, but they accept any number of arguments)? Should include a test for this.
================
Comment at: lib/Sema/SemaDeclAttr.cpp:1520-1522
+ ParmVarDecl *PD = dyn_cast<ParmVarDecl>(D);
+ if (!PD)
+ return;
----------------
Is there ever a case where this if statement will early return? I think you can just use `cast<ParmVarDecl>(D)->getType()` below.
================
Comment at: lib/Sema/SemaExpr.cpp:11180
+ if (const auto *DRE =
+ dyn_cast_or_null<DeclRefExpr>(RHS.get()->IgnoreImpCasts())) {
+ const auto *D = DRE->getDecl();
----------------
Why `dyn_cast_or_null`? I didn't think `IgnoreImpCasts()` could return null.
================
Comment at: lib/Sema/SemaExpr.cpp:11181
+ dyn_cast_or_null<DeclRefExpr>(RHS.get()->IgnoreImpCasts())) {
+ const auto *D = DRE->getDecl();
+ if (D->hasAttr<NoEscapeAttr>()) {
----------------
Don't use `auto`.
================
Comment at: lib/Sema/SemaExpr.cpp:11184
+ Diag(DRE->getLocation(), diag::err_noescape_assignment)
+ << D->getName();
+ Diag(D->getLocation(), diag::note_noescape_parameter) << 0;
----------------
Can drop the `getName()` call.
================
Comment at: lib/Sema/SemaExpr.cpp:13682
+ if (Var->hasAttr<NoEscapeAttr>()) {
+ S.Diag(Loc, diag::err_noescape_block_capture) << Var->getName();
+ S.Diag(Var->getLocation(), diag::note_noescape_parameter) << 0;
----------------
Can drop the `getName()` call.
================
Comment at: lib/Sema/SemaStmt.cpp:3203
+ if (const auto *DRE = dyn_cast_or_null<DeclRefExpr>(RetValExp)) {
+ const auto *D = DRE->getDecl();
+ if (D->hasAttr<NoEscapeAttr>()) {
----------------
Don't use `auto`.
================
Comment at: lib/Sema/SemaStmt.cpp:3205
+ if (D->hasAttr<NoEscapeAttr>()) {
+ Diag(DRE->getLocation(), diag::err_noescape_returned) << D->getName();
+ Diag(D->getLocation(), diag::note_noescape_parameter) << 0;
----------------
Can drop `getName()`.
https://reviews.llvm.org/D32210
More information about the cfe-commits
mailing list