diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertyAccessorSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertyAccessorSymbol.cs index d8a8226b186304c752b74e9b94a173d90acf6bc0..ef4209c5cd4688aa42163bc62476960299527906 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertyAccessorSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertyAccessorSymbol.cs @@ -431,10 +431,14 @@ internal override bool IsDeclaredReadOnly return true; } - // We can't emit the synthesized attribute for netmodules, so in this case we consider auto-getters **not** implicitly readonly. - if (DeclaringCompilation.Options.OutputKind == OutputKind.NetModule && - DeclaringCompilation.GetWellKnownType(WellKnownType.System_Runtime_CompilerServices_IsReadOnlyAttribute).IsErrorType()) + // If we have IsReadOnly..ctor, we can use the attribute. Otherwise, we need to NOT be a netmodule and the type must not already exist in order to synthesize it. + var isReadOnlyAttributeUsable = DeclaringCompilation.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_IsReadOnlyAttribute__ctor) != null || + (DeclaringCompilation.Options.OutputKind != OutputKind.NetModule && + DeclaringCompilation.GetWellKnownType(WellKnownType.System_Runtime_CompilerServices_IsReadOnlyAttribute) is MissingMetadataTypeSymbol); + + if (!isReadOnlyAttributeUsable) { + // if the readonly attribute isn't usable, don't implicitly make auto-getters readonly. return false; } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/ReadOnlyStructsTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/ReadOnlyStructsTests.cs index 3dde04e41406d0445caedd546da34fbbbd8ff8e2..f52907640c5cb25e0a20c07bf53f21664f9f1398 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/ReadOnlyStructsTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/ReadOnlyStructsTests.cs @@ -1484,17 +1484,17 @@ public struct S public int P1 { get; private set; } } "; - var moduleComp = CreateCompilation(csharp, options: TestOptions.DebugModule, targetFramework: TargetFramework.Mscorlib45); - moduleComp.VerifyDiagnostics( - // (12,21): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.IsReadOnlyAttribute..ctor' - // public int P1 { get; private set; } - Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "get").WithArguments("System.Runtime.CompilerServices.IsReadOnlyAttribute", ".ctor").WithLocation(12, 21)); + var moduleMetadata = CreateCompilation(csharp, options: TestOptions.DebugModule, targetFramework: TargetFramework.Mscorlib45).EmitToImageReference(); + var moduleComp = CreateCompilation("", new[] { moduleMetadata }); + var moduleGetterAttributes = moduleComp.GetMember("S.P1").GetMethod.GetAttributes(); + Assert.Equal(1, moduleGetterAttributes.Length); + Assert.Equal("CompilerGeneratedAttribute", moduleGetterAttributes[0].AttributeClass.Name); - var dllComp = CreateCompilation(csharp, options: TestOptions.DebugDll, targetFramework: TargetFramework.Mscorlib45); - dllComp.VerifyDiagnostics( - // (12,21): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.IsReadOnlyAttribute..ctor' - // public int P1 { get; private set; } - Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "get").WithArguments("System.Runtime.CompilerServices.IsReadOnlyAttribute", ".ctor").WithLocation(12, 21)); + var dllMetadata = CreateCompilation(csharp, options: TestOptions.DebugDll, targetFramework: TargetFramework.Mscorlib45).EmitToImageReference(); + var dllComp = CreateCompilation("", new[] { dllMetadata }); + var dllGetterAttributes = dllComp.GetMember("S.P1").GetMethod.GetAttributes(); + Assert.Equal(1, dllGetterAttributes.Length); + Assert.Equal("CompilerGeneratedAttribute", dllGetterAttributes[0].AttributeClass.Name); } [Fact]