This is an archive of the discontinued LLVM Phabricator instance.

[Sema] Don't set BlockDecl's DoesNotEscape bit If the block is being passed to a function taking a reference parameter
ClosedPublic

Authored by ahatanak on Apr 22 2021, 12:00 PM.

Details

Summary

In the following example, the block passed to the function is marked as noescape, which is incorrect as the noescape attribute applies to the reference:

typedef void (^BlockTy)();
 __block S6 b5;
void noescapeFuncRefParam1(__attribute__((noescape)) BlockTy &&);
noescapeFuncRefParam1(^{ (void)b5; });

This partially fixes PR50043.

rdar://77030453

Diff Detail

Event Timeline

ahatanak requested review of this revision.Apr 22 2021, 12:00 PM
ahatanak created this revision.
rjmccall added inline comments.Apr 22 2021, 9:59 PM
clang/lib/Sema/SemaExpr.cpp
5917

We need to be checking that the parameter type is a block pointer type. A parameter of a type like id or void* does not have the enhanced semantics of noescape for blocks.

The inevitable weird C++ test case is:

struct NoescapeCtor {
  NoescapeCtor(__attribute__((noescape)) void (^)());
};
struct EscapeCtor {
  EscapeCtor(void (^)());
};

void helper1(NoescapeCtor a);
void test1() { helper1(^{}); } // <- should be noescape

void helper2(NoescapeCtor &&a);
void test2() { helper2(^{}); } // <- should be noescape

void helper3(__attribute__((noescape)) EscapeCtor &&a);
void test3() { helper3(^{}); } // <- should not be noescape

You should probably also test that calls to function templates behave according to the instantiated type of the parameter. I expect that that should just fall out from this implementation, which I think only triggers on non-dependent calls.

ahatanak added inline comments.Apr 23 2021, 2:46 PM
clang/lib/Sema/SemaExpr.cpp
5917

I understand why the blocks should or shouldn't be noescape in the C++ example, but I'm not sure I understand the comment about id and void*.

Do you mean the DoesNotEscape bit shouldn't be set in the following example?

void helper(__attribute__((noescape)) id);

void test() {
  S s;
  helper(^{ (void)s; });
}
rjmccall added inline comments.Apr 23 2021, 2:58 PM
clang/lib/Sema/SemaExpr.cpp
5917

The noescape documentation says:

Additionally, when the parameter is a block pointer, the same restriction applies to copies of the block.

That's the restriction that makes the noescape block optimization sound, and it doesn't apply when the parameter does not have block pointer type. So yes, DoesNotEscape shouldn't be set in that example.

ahatanak added inline comments.Apr 23 2021, 3:19 PM
clang/lib/Sema/SemaExpr.cpp
5917

Ah, I see.

ahatanak updated this revision to Diff 340234.Apr 23 2021, 9:14 PM

Check that the parameter has a block pointer type. Add more test cases.

ahatanak added inline comments.Apr 23 2021, 9:38 PM
clang/test/SemaObjCXX/noescape.mm
20

I didn't realize clang rejects noescape on parameters of template functions. I think this should be fixed in a followup patch.

This revision is now accepted and ready to land.Apr 28 2021, 10:18 PM