Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow RequiresUnreferencedCode on classes and structs #1742

Closed
eerhardt opened this issue Jan 12, 2021 · 15 comments · Fixed by #2143
Closed

Allow RequiresUnreferencedCode on classes and structs #1742

eerhardt opened this issue Jan 12, 2021 · 15 comments · Fixed by #2143
Assignees
Labels

Comments

@eerhardt
Copy link
Member

Some types are inherently not trim compatible. Take, for example, BinaryFormatter. Virtually anything you do with the type is not going to be trim compatible.

Today, we only allow RequiresUnreferencedCodeAttribute on methods and constructors.

https://github.com/dotnet/runtime/blob/d2e1a86434d1c0b74d75604b4cf9fdca100108c3/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/RequiresUnreferencedCodeAttribute.cs#L14-L15

When trying to annotate the implementation of BinaryFormatter, it is causing almost every method in the library to be marked as RequiresUnreferencedCode. This is a lot of changes when just putting the attribute on a whole class would be a lot easier.

We should change the ILLinker to support RequiresUnreferencedCodeAttribute on classes and structs, and possibly interfaces.

@agocke @vitek-karas @MichalStrehovsky

@MichalStrehovsky
Copy link
Member

Is that just syntactic sugar to save us from annotating multiple methods or do we expect more semantics from this?

E.g. do derived types inherit this setting? Does it propagate to nested types?

Putting RequiresUnreferencedCode on some methods is problematic. E.g. annotating a GetHashCode override as RequiresUnreferenced is going to warn because Object.GetHashCode also needs to be annotated like that, otherwise it's unenforceable.

@marek-safar
Copy link
Contributor

Could you link the code you are referring to? I'm not sure this will be useful when used in non-trivial code. I'd expect that constructors and properties rarely need RequiresUnreferencedCode.

@eerhardt
Copy link
Member Author

Could you link the code you are referring to?

See the BinaryObjectWriter.cs, BinaryObjectReader.cs, and BinaryParser.cs files in dotnet/runtime#46964.

@marek-safar
Copy link
Contributor

I don't see that as good evidence that we need it right now.

BinaryParser (only 4 internal methods need it out of about 35)
BinaryObjectReader (1 internal method out of 4 methods)
BinaryObjectReader (3 internal methods out of 7 methods)

@MichalStrehovsky
Copy link
Member

@agocke Brought this up on our 1:1 yesterday. He suggested a possible semantic for this that might work for this: treat it the same as the C# compiler treats the ObsoleteAttribute. Basically, on classes, it would behave the same as if we annotated all the constructors and static methods as RUC. We would also suppress all trimming warnings within instance methods, but we would not treat them like RUC at their callsites (this avoids the problem of ToString) - this assumes that the unsafe operation is creating the type - after that, all bets are off.

It's not easily extensible to structs, but I posit that nobody is going to miss that.

One possible complication is static virtual methods that are being added to C# and runtime as we speak. I don't know what the solution for that would be (they allow calling static methods indirectly). Maybe we can say that you can't put the attribute on a type that implements static interface methods and this will be a warning. Or maybe the C# team will come up with something clever.

@eerhardt
Copy link
Member Author

it would behave the same as if we annotated all the constructors and static methods as RUC

I would also assume any usages of the Type, say for example: typeof(MyGeneric<>).MakeGenericType(typeof(MyRUCType))

@MichalStrehovsky
Copy link
Member

I would also assume any usages of the Type, say for example: typeof(MyGeneric<>).MakeGenericType(typeof(MyRUCType))

That by itself doesn't look problematic. But if MyGeneric has a new() constraint or a method/constructor annotation on T, then yes, it probably should warn using the rules we have for RUC-annotated reflected methods.

We need to be careful about when we generate these warnings because it's easy to get into a situation where "if the type wasn't trimmed away, we will warn" because those are hard to suppress and generate warnings for (e.g. should the fact that a type implements IComparer<MyRUCType> trigger warnings?).

@eerhardt
Copy link
Member Author

Here's another case where it would be beneficial to have RequiresUnreferencedCode on a whole type:

krwq/runtime-1@6ad21f3

We are up to almost 800 RequiresUnreferencedCode attributes trying to annotate each method separately.

@eerhardt
Copy link
Member Author

eerhardt commented Jul 6, 2021

Was this ever implemented in the linker? I see usages of this trying to pop up. ex. dotnet/runtime#55108.

@vitek-karas
Copy link
Member

@tlakollo is working on it - it's tentatively planned for 6 right now (but no guarantees as we haven't got it working end to end yet).

@eerhardt
Copy link
Member Author

eerhardt commented Jul 6, 2021

Thanks. For now I'll recommend people don't use this feature until it is implemented. If we don't get it in for 6, we need to revert dotnet/runtime#50064 then.

@agocke
Copy link
Member

agocke commented Jul 6, 2021

@tlakollo is working on this right now has his highest priority. Hope to have it available shortly

@agocke
Copy link
Member

agocke commented Jul 17, 2021

@tlakollo Still need analyzer support, right?

@agocke agocke reopened this Jul 17, 2021
@tlakollo
Copy link
Contributor

Yes, the Merged PR would only work for Linker

@tlakollo
Copy link
Contributor

This should be already working for linker and analyzer see #2330, closing

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants