This is an archive of the discontinued LLVM Phabricator instance.

[attributes] Add a family of OS_CONSUMED, OS_RETURNS and OS_RETURNS_RETAINED attributes
ClosedPublic

Authored by george.karpenkov on Nov 26 2018, 12:14 PM.

Details

Summary

The addition adds three attributes for communicating ownership,
analogous to existing NS_ and CF_ attributes.
The attributes are meant to be used for communicating ownership of all objects in XNU (Darwin kernel) and all of the kernel modules.
The ownership model there is very similar, but still different from the Foundation model, so we think that introducing a new family of attributes is appropriate.

The addition required a sizeable refactoring of the existing code for CF_ and NS_ ownership attributes,
due to tight coupling and the fact that differentiating between the types was previously done using a boolean.

Diff Detail

Repository
rL LLVM

Event Timeline

aaron.ballman added inline comments.Nov 27 2018, 1:42 PM
clang/include/clang/Basic/Attr.td
834 ↗(On Diff #175311)

No new undocumented attributes, please. (Same for the other attributes.)

837 ↗(On Diff #175311)

Are there no subjects for this attribute?

842 ↗(On Diff #175311)

Or this one?

clang/lib/Sema/SemaDeclAttr.cpp
395–400 ↗(On Diff #175311)

Did clang-format do this?

417 ↗(On Diff #175311)

T &&ExtraArg and std::forward it below?

418 ↗(On Diff #175311)

Missing && here, no?

430 ↗(On Diff #175311)

I don't see a strong relationship between this function name and the fact that the check function is doing something with type checking. The function sounds more generic than it really is.

434 ↗(On Diff #175311)

I don't like this being a cast<> here. I would do: if (auto *VD = dyn_cast<ValueDecl>(D)) { ... } to avoid the assertion.

436 ↗(On Diff #175311)

Is this top-level const because you planned to assign to a const reference, or do you really want the copy here? If you want the copy, please drop the const.

4851 ↗(On Diff #175311)

Spurious newline.

clang/test/SemaTemplate/attributes.cpp
57–76 ↗(On Diff #175311)

These should be in a test in Sema, not SemaTemplate (they're not related to template instantiation).

george.karpenkov marked 18 inline comments as done.
george.karpenkov added inline comments.
clang/include/clang/Basic/Attr.td
834 ↗(On Diff #175311)

OK

837 ↗(On Diff #175311)

I've copied it from the other family of attributes; TBH I'm not sure what the field is doing. I'll see whether I can come up with a good value.

842 ↗(On Diff #175311)

OK, same as above --- I'll try to put something reasonable there.

clang/lib/Sema/SemaDeclAttr.cpp
395–400 ↗(On Diff #175311)

It's a different function from the previous one -- I have introduced another handleSimpleAttribute which takes a SourceRange and a SpellingIndex directly, and now the previous one calls it.

417 ↗(On Diff #175311)

OK

430 ↗(On Diff #175311)

Ideally it should really take a check on a Decl, and not a type,
but in this case it led to unnecessary code duplication (as in one of the use cases only type, and not the decl is available).
I think it's quite generic - it performs and check on the declaration type.

In such situations I usually favor the YAGNI principle - leave it like this, and if someone needs a check on a decl, and not an attribute, this function could easily be generalized.

434 ↗(On Diff #175311)

OK. In that case being not a value decl would implicitly fial the diagnostic check.

436 ↗(On Diff #175311)

I dislike having references to returned values, as RVO would avoid the copy anyway.

Conceptually, it should be a reference, but in this case we don't need it (due to RVO),
and having an extra copy before any diagnostic is emitted won't hurt.

Later on it is passed as a parameter to a function accepting a const reference.

4851 ↗(On Diff #175311)

I like to follow Google style guide with a newline preceding each comment, but OK.

clang/test/SemaTemplate/attributes.cpp
57–76 ↗(On Diff #175311)

OK

aaron.ballman added inline comments.Nov 27 2018, 4:24 PM
clang/include/clang/Basic/Attr.td
1634 ↗(On Diff #175593)

Should this also point to RetainBehaviorDocs now?

837 ↗(On Diff #175311)

The subject list specifies what kind of entities the attribute can appertain to; it takes care of some of the automated testing for attributes so you don't have to do the work manually.

clang/include/clang/Basic/AttrDocs.td
860 ↗(On Diff #175593)

You can re-flow the documentation for 80-col.

882–883 ↗(On Diff #175593)

These are probably meant to be os_* and not cf_*.

clang/lib/Sema/SemaDeclAttr.cpp
395–400 ↗(On Diff #175311)

My comment was more about the formatting. I saw that this is a new overload, but the old formatting was very strange. It looks correct now.

430 ↗(On Diff #175311)

I think it's quite generic - it performs and check on the declaration type.

Not all declarations have types. For instance, you can apply an attribute to a namespace declaration (such as [[deprecated]]). So my concern is more that this function isn't actually generic when it sounds like it is.

In such situations I usually favor the YAGNI principle - leave it like this, and if someone needs a check on a decl, and not an attribute, this function could easily be generalized.

Yeah, I don't think we need to change the behavior of the function, but I am wondering if it makes sense to rename it to handleSimpleAttributeWithTypeCheck() or some-such to make it more clear that the attribute must appertain to a declaration with a type. Alternatively, instead of taking a Decl *, it could accept a ValueDecl * instead and force the user to only pass in declarations with types to the call.

436 ↗(On Diff #175311)

I'm reluctantly okay with using value semantics here (I have a preference for using const reference semantics instead so we can avoid a needless local copy), but the top-level const should go in that case (we don't typically use that idiom in the project). I was only asking because I could not tell if that was a typo for const Sema::SemaDiagnosticBuilder & or not.

clang/test/Sema/attr-osobject.cpp
1 ↗(On Diff #175593)

This doesn't need to pass -std=c++11.

4 ↗(On Diff #175593)

Can you run this file through clang-format?

22 ↗(On Diff #175593)

You should also add tests that ensure that the attribute does not accept arguments and doesn't appertain to things that are not functions.

Related Q: should all of these attributes also appertain to function pointers? (This may be orthogonal to this patch.)

george.karpenkov marked 10 inline comments as done.
george.karpenkov added inline comments.
clang/lib/Sema/SemaDeclAttr.cpp
430 ↗(On Diff #175311)

OK, let's accept a ValueDecl.

436 ↗(On Diff #175311)

Dropping const.
I don't think we should have a reference here, as then there is no clear owner for the builder, and it becomes easy to end up with a dead reference.

clang/test/Sema/attr-osobject.cpp
22 ↗(On Diff #175593)

Attributes should only apply to pointers to objects (inside the analyzer it's even more restricted: only pointers to objects inheriting from OSObject).

aaron.ballman added inline comments.Nov 28 2018, 4:47 AM
clang/include/clang/Basic/Attr.td
839 ↗(On Diff #175602)

The CFReturnsRetained (and NotRetained) use a commented-out subject list that includes ObjCProperty. Do the OS functions also apply to ObjCProperty objects? I believe I added the above commented out because we couldn't automate something about it, and I vaguely recall the subject list was my best effort at gleaning the subjects (so it might be inaccurate).

clang/lib/Sema/SemaDeclAttr.cpp
4773–4778 ↗(On Diff #175602)

This doesn't look formatted properly to me. Did clang-format do this?

4789 ↗(On Diff #175602)

Can remove spurious newline.

clang/test/Sema/attr-osobject.cpp
22 ↗(On Diff #175593)

Do the same kind of tests for os_returns_retained and os_returns_not_retained.

You should also add an Objective-C test for their methods and properties (those tests can be positive tests showing that no diagnostics are expected).

george.karpenkov marked 5 inline comments as done.
george.karpenkov added inline comments.
clang/include/clang/Basic/Attr.td
839 ↗(On Diff #175602)

No, they shouldn't apply to properties.

aaron.ballman added inline comments.Nov 28 2018, 11:05 AM
clang/include/clang/Basic/Attr.td
839 ↗(On Diff #175602)

handleXReturnsXRetainedAttr() suggests otherwise for the other attributes, so is there a reason this one is different?

For instance: https://godbolt.org/z/stN5rO

clang/lib/Sema/SemaDeclAttr.cpp
4838 ↗(On Diff #175726)

This seems to imply that an ObjCPropertyDecl is acceptable to all of the returns_*_retained attributes (was there before your refactoring).

4862 ↗(On Diff #175726)

And then this suggests that NS and OS do not accept properties (similar below for CF).

If NS and CF are expected to work on properties, we should probably update this diagnostic (doesn't have to be part of this patch). If they aren't supposed to work on properties, then we should fix the logic.

george.karpenkov marked 2 inline comments as done.
george.karpenkov added inline comments.
clang/include/clang/Basic/Attr.td
839 ↗(On Diff #175602)

Hm, that's an interesting point, thanks for bringing this up.

On one hand, adding OS_RETURNS_RETAINED to properties makes no sense - the semantics of the program is really weird if accessing the property transfers the ownership.
But on the other hand it's explicitly allowed and tested in attr-cf_returns on CF_* properties, so we should probably allow it as well.

clang/lib/Sema/SemaDeclAttr.cpp
4862 ↗(On Diff #175726)

They do work, and it's actually explicitly tested. I think for the purpose of symmetry we should also support it for OS_* attributes then.

Since a lot of code relies on behavior of NS_* properties for code generation, I'm not going to change the logic for that behavior, unless the actual need arises.
FWIW the error message is actually correct when the attribute is added to the property of the unexpected type.

aaron.ballman accepted this revision.Nov 29 2018, 5:38 AM

LGTM aside from a small documentation nit.

clang/include/clang/Basic/AttrDocs.td
853 ↗(On Diff #175731)

You should add a quick note somewhere in here that some of these attributes appertains to functions, Objective-C methods, and Objective-C properties.

clang/lib/Sema/SemaDeclAttr.cpp
4862 ↗(On Diff #175726)

FWIW the error message is actually correct when the attribute is added to the property of the unexpected type.

I think it's incorrect -- that error message results in this, which doesn't mention ObjC properties: https://godbolt.org/z/UZHHN_

I can fix this up in a separate patch, however.

This revision is now accepted and ready to land.Nov 29 2018, 5:38 AM
This revision was automatically updated to reflect the committed changes.
aaron.ballman added inline comments.Nov 30 2018, 6:20 AM
cfe/trunk/lib/Sema/SemaDeclAttr.cpp
4862

I mentioned that I could fix this up in another patch, but there's a different subtlety here -- you can apply NSReturnsRetained and friends to types. See test\SemaObjC\attr-ns_returns_retained.m for an example -- where it's being added to a block type. It also seems to appertain to block literals (test\SemaObjC\block-literal-with-attribute.m).

Should the OS versions also apply to types and block literals?

george.karpenkov marked an inline comment as done.Nov 30 2018, 11:23 AM
george.karpenkov added inline comments.
cfe/trunk/lib/Sema/SemaDeclAttr.cpp
4862

OS versions should not apply to block literals, neither they should be applicable to block types.

aaron.ballman added inline comments.Nov 30 2018, 11:24 AM
cfe/trunk/lib/Sema/SemaDeclAttr.cpp
4862

Can you add some tests to ensure it's properly diagnosed?

george.karpenkov marked an inline comment as done.Nov 30 2018, 5:40 PM
george.karpenkov added inline comments.
cfe/trunk/lib/Sema/SemaDeclAttr.cpp
4862

@aaron.ballman Do you mean something like this?

diff --git a/clang/test/Sema/attr-osobject.mm b/clang/test/Sema/attr-osobject.mm
index dbd9122a8fa..ffb4394e4bc 100644
--- a/clang/test/Sema/attr-osobject.mm
+++ b/clang/test/Sema/attr-osobject.mm
@@ -1,6 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
-
-// expected-no-diagnostics
+// RUN: %clang_cc1 -fsyntax-only -fblocks -verify %s

 struct S {};

@@ -9,3 +7,5 @@ @interface I
   - (S*) generateS __attribute__((os_returns_retained));
   - (void) takeS:(S*) __attribute__((os_consumed)) s;
 @end
+
+typedef __attribute__((os_returns_retained)) id (^blockType)(); // expected-warning{{'os_returns_retained' attribute only applies to functions, Objective-C methods, and Objective-C properties}}
aaron.ballman added inline comments.Dec 1 2018, 9:46 AM
cfe/trunk/lib/Sema/SemaDeclAttr.cpp
4862

Yup! Also:

__auto_type b = ^ id (id filter)  __attribute__((os_returns_retained))  {
  return filter;
};

This is accepted by ns_returns_retained, so it would be good to clearly show it's not supported by os_returns_retained.

george.karpenkov marked an inline comment as done.Dec 5 2018, 5:25 PM
george.karpenkov added inline comments.
cfe/trunk/lib/Sema/SemaDeclAttr.cpp
4862