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

Verify synthesized RequiresLocationAttribute cannot be accessed by fnptrs #69328

Merged
merged 7 commits into from
Aug 11, 2023
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1191,13 +1191,158 @@ public unsafe void M(delegate*<ref readonly int, void> p) { }
}
""";
var comp = CreateCompilation(source, options: TestOptions.UnsafeDebugDll);
comp.MakeTypeMissing(WellKnownType.System_Runtime_CompilerServices_RequiresLocationAttribute);
comp.VerifyDiagnostics(
// (3,36): error CS0518: Predefined type 'System.Runtime.CompilerServices.RequiresLocationAttribute' is not defined or imported
// public unsafe void M(delegate*<ref readonly int, void> p) { }
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "ref readonly int").WithArguments("System.Runtime.CompilerServices.RequiresLocationAttribute").WithLocation(3, 36));
}

[Fact]
public void FunctionPointer_NoAttribute_PlusNormalMethod()
{
var source = """
class C
{
public unsafe void M1(delegate*<ref readonly int, void> p) { }
public void M2(ref readonly int p) { }
}
""";
var comp = CreateCompilation(source, options: TestOptions.UnsafeDebugDll);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The core CreateCompilation helper is expected to roll forward to the latest target framework as we move forward. At the moment this references the net7.0 assemblies but will move to net8.0 (likely early 2024). At that point the test will fail because this will succeed since RequiresLocationAttribute will be available. Think this test should specify TargetFramework.Net70 explicitly to avoid that future issue.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is that right? Seems that the default target framework is netstandard2.0. Otherwise, I would probably need to change a lot of tests in this file because for example all function pointer tests include the attribute definition as source.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My mistake. Your correct this defaults to TargteFramework.Standard not TargetFramework.Latest.

comp.VerifyDiagnostics(
// (3,37): error CS0518: Predefined type 'System.Runtime.CompilerServices.RequiresLocationAttribute' is not defined or imported
// public unsafe void M1(delegate*<ref readonly int, void> p) { }
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "ref readonly int").WithArguments("System.Runtime.CompilerServices.RequiresLocationAttribute").WithLocation(3, 37));
}

[Fact]
public void FunctionPointer_InternalAttribute()
{
// Attribute is synthesized for Assembly1, but it's not visible to Assembly2.
var source1 = """
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Assembly2")]
internal class C
{
public void M(ref readonly int p) { }
}
""";
var comp1 = CreateCompilation(source1, assemblyName: "Assembly1").VerifyDiagnostics();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar feedback about all the CreateCompilation uses in this particular PR.

var comp1Ref = comp1.EmitToImageReference();
var source2 = """
class D
{
public unsafe object M(delegate*<ref readonly int, void> p)
{
var c = new C();
int x = 5;
c.M(in x);
var attr = new System.Runtime.CompilerServices.RequiresLocationAttribute();
return attr;
}
}
""";
var comp2 = CreateCompilation(source2, new[] { comp1Ref }, assemblyName: "Assembly2", options: TestOptions.UnsafeDebugDll);
comp2.VerifyDiagnostics(
// (3,38): error CS0518: Predefined type 'System.Runtime.CompilerServices.RequiresLocationAttribute' is not defined or imported
// public unsafe object M(delegate*<ref readonly int, void> p)
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "ref readonly int").WithArguments("System.Runtime.CompilerServices.RequiresLocationAttribute").WithLocation(3, 38),
// (8,56): error CS0234: The type or namespace name 'RequiresLocationAttribute' does not exist in the namespace 'System.Runtime.CompilerServices' (are you missing an assembly reference?)
// var attr = new System.Runtime.CompilerServices.RequiresLocationAttribute();
Diagnostic(ErrorCode.ERR_DottedTypeNameNotFoundInNS, "RequiresLocationAttribute").WithArguments("RequiresLocationAttribute", "System.Runtime.CompilerServices").WithLocation(8, 56));

// Assembly1 defines the attribute in source and has IVT to Assembly2, so the attribute is visible to Assembly2.
var comp1b = CreateCompilation(new[] { source1, RequiresLocationAttributeDefinition }, assemblyName: "Assembly1").VerifyDiagnostics();
var comp1bRef = comp1b.EmitToImageReference();
var comp2b = CreateCompilation(source2, new[] { comp1bRef }, assemblyName: "Assembly2", options: TestOptions.UnsafeDebugDll);
comp2b.VerifyDiagnostics();

// Assembly1 defines the attribute in source but doesn't have IVT to Assembly3, so the attribute isn't visible to Assembly3.
var source3 = """
class D
{
public unsafe object M(delegate*<ref readonly int, void> p)
{
var attr = new System.Runtime.CompilerServices.RequiresLocationAttribute();
return attr;
}
}
""";
var comp3 = CreateCompilation(source3, new[] { comp1bRef }, assemblyName: "Assembly3", options: TestOptions.UnsafeDebugDll);
comp3.VerifyDiagnostics(
// (3,38): error CS0518: Predefined type 'System.Runtime.CompilerServices.RequiresLocationAttribute' is not defined or imported
// public unsafe object M(delegate*<ref readonly int, void> p)
Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "ref readonly int").WithArguments("System.Runtime.CompilerServices.RequiresLocationAttribute").WithLocation(3, 38),
// (5,56): error CS0122: 'RequiresLocationAttribute' is inaccessible due to its protection level
// var attr = new System.Runtime.CompilerServices.RequiresLocationAttribute();
Diagnostic(ErrorCode.ERR_BadAccess, "RequiresLocationAttribute").WithArguments("System.Runtime.CompilerServices.RequiresLocationAttribute").WithLocation(5, 56));
}

[Fact]
public void FunctionPointer_DefineManually_LaterDefinedInRuntime()
{
// Library defines an API with function pointer, manually declaring the attribute.
var source1 = """
public class C
{
public unsafe void M(delegate*<ref readonly int, void> f)
{
int x = 123;
f(in x);
}
}
""";
var comp1v1 = CreateCompilation(new[] { source1, RequiresLocationAttributeDefinition }, assemblyName: "Assembly1", options: TestOptions.UnsafeReleaseDll);
comp1v1.VerifyDiagnostics();
var comp1v1Ref = comp1v1.EmitToImageReference();

// Consumer can use the API.
var source2 = """
public class D
{
public unsafe void M()
{
new C().M(&F);
}
static void F(ref readonly int x) => System.Console.Write("F" + x);
}
""";
var comp2 = CreateCompilation(source2, new[] { comp1v1Ref }, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics();
var comp2Ref = comp2.EmitToImageReference();

var source3 = """
try
{
new D().M();
}
catch (System.MissingMethodException e)
{
System.Console.Write(e.Message);
}
""";
CompileAndVerify(source3, new[] { comp1v1Ref, comp2Ref }, expectedOutput: "F123").VerifyDiagnostics();

// .NET runtime declares the attribute.
var source4 = """
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
public sealed class RequiresLocationAttribute : Attribute
{
}
}
""";
var comp4 = CreateCompilation(source4).VerifyDiagnostics();
var comp4Ref = comp4.EmitToImageReference();

// Library is recompiled against the newest runtime.
var comp1v2 = CreateCompilation(source1, new[] { comp4Ref }, assemblyName: "Assembly1", options: TestOptions.UnsafeReleaseDll);
comp1v2.VerifyDiagnostics();
var comp1v2Ref = comp1v2.EmitToImageReference();

// That breaks the consumer.
CompileAndVerify(source3, new[] { comp1v2Ref, comp2Ref, comp4Ref },
expectedOutput: "Method not found: 'Void C.M(Void (Int32 ByRef))'.").VerifyDiagnostics();
}

jjonescz marked this conversation as resolved.
Show resolved Hide resolved
[Fact]
public void FunctionPointer_Local()
{
Expand Down Expand Up @@ -1231,7 +1376,6 @@ unsafe void M()
}
""";
var comp = CreateCompilation(source, options: TestOptions.UnsafeDebugDll);
comp.MakeTypeMissing(WellKnownType.System_Runtime_CompilerServices_RequiresLocationAttribute);
comp.VerifyDiagnostics(
// (5,19): error CS0518: Predefined type 'System.Runtime.CompilerServices.RequiresLocationAttribute' is not defined or imported
// delegate*<ref readonly int, void> p = null;
Expand Down