diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Attributes.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Attributes.cs index 56b8ec335ae06..b06635bcc4edd 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Attributes.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Attributes.cs @@ -155,7 +155,7 @@ private Binder SkipSemanticModelBinder() private static BoundAttribute BindAttributeCore(Binder binder, AttributeSyntax node, NamedTypeSymbol attributeType, Symbol? attributedMember, BindingDiagnosticBag diagnostics) { Debug.Assert(binder.SkipSemanticModelBinder() == binder.GetRequiredBinder(node).SkipSemanticModelBinder()); - binder = binder.WithAdditionalFlags(BinderFlags.AttributeArgument); + Debug.Assert(binder.InAttributeArgument); // If attribute name bound to an error type with a single named type // candidate symbol, we want to bind the attribute constructor diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs index 538a8090f72ab..ab79a8b8e3c72 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs @@ -2717,7 +2717,7 @@ private bool MemberGroupFinalValidationAccessibilityChecks(BoundExpression? rece diagnostics.Add(ErrorCode.ERR_ObjectRequired, node.Location, memberSymbol); return true; } - else if (WasImplicitReceiver(receiverOpt)) + else if (WasImplicitReceiver(receiverOpt) && !(IsInsideNameof && Compilation.IsFeatureEnabled(MessageID.IDS_FeatureInstanceMemberInNameof))) { if (InFieldInitializer && !ContainingType!.IsScriptClass || InConstructorInitializer || InAttributeArgument) { diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs index 7634bda3b55aa..abf24c2296825 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs @@ -35,6 +35,12 @@ internal partial class Binder /// True if a reference to "this" is available. internal bool HasThis(bool isExplicit, out bool inStaticContext) { + if (!isExplicit && IsInsideNameof && Compilation.IsFeatureEnabled(MessageID.IDS_FeatureInstanceMemberInNameof)) + { + inStaticContext = false; + return true; + } + var memberOpt = this.ContainingMemberOrLambda?.ContainingNonLambdaMember(); if (memberOpt?.IsStatic == true) { diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs index b1165208e4ac6..71c7c0f79fb50 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs @@ -2351,6 +2351,7 @@ private bool TryBindNameofOperator(InvocationExpressionSyntax node, BindingDiagn if (node.MayBeNameofOperator()) { var binder = this.GetBinder(node); + Debug.Assert(binder.Flags == this.Flags); if (binder.EnclosingNameofArgument == node.ArgumentList.Arguments[0].Expression) { result = binder.BindNameofOperatorInternal(node, diagnostics); diff --git a/src/Compilers/CSharp/Portable/Binder/LocalBinderFactory.cs b/src/Compilers/CSharp/Portable/Binder/LocalBinderFactory.cs index ecc379f4611ba..214620d607059 100644 --- a/src/Compilers/CSharp/Portable/Binder/LocalBinderFactory.cs +++ b/src/Compilers/CSharp/Portable/Binder/LocalBinderFactory.cs @@ -478,7 +478,7 @@ public override void VisitEqualsValueClause(EqualsValueClauseSyntax node) public override void VisitAttribute(AttributeSyntax node) { - var attrBinder = new ExpressionVariableBinder(node, _enclosing); + var attrBinder = new ExpressionVariableBinder(node, _enclosing.WithAdditionalFlags(BinderFlags.AttributeArgument)); AddToMap(node, attrBinder); if (node.ArgumentList?.Arguments.Count > 0) diff --git a/src/Compilers/CSharp/Portable/Compilation/PublicSemanticModel.cs b/src/Compilers/CSharp/Portable/Compilation/PublicSemanticModel.cs index a20b8224e5fd1..4886d23b4700f 100644 --- a/src/Compilers/CSharp/Portable/Compilation/PublicSemanticModel.cs +++ b/src/Compilers/CSharp/Portable/Compilation/PublicSemanticModel.cs @@ -28,7 +28,7 @@ protected AttributeSemanticModel CreateModelForAttribute(Binder enclosingBinder, attributeType, aliasOpt, attributeTarget, - enclosingBinder.WithAdditionalFlags(BinderFlags.AttributeArgument), + enclosingBinder, containingModel?.GetRemappedSymbols()); Symbol? getAttributeTarget(SyntaxNode? targetSyntax) diff --git a/src/Compilers/CSharp/Test/Emit3/Semantics/CollectionExpressionTests.cs b/src/Compilers/CSharp/Test/Emit3/Semantics/CollectionExpressionTests.cs index bbf72a68dc844..25d23480f1c35 100644 --- a/src/Compilers/CSharp/Test/Emit3/Semantics/CollectionExpressionTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/Semantics/CollectionExpressionTests.cs @@ -47359,5 +47359,112 @@ class D CompileAndVerify(CreateCompilationWithSpan([source, CollectionBuilderAttributeDefinition]), expectedOutput: "").VerifyDiagnostics(); } + + [Fact] + [WorkItem("https://github.com/dotnet/roslyn/issues/81576")] + public void Issue81576_01() + { + var source = """ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Runtime.CompilerServices; + + [CollectionBuilder(typeof(MyFancyCollection), nameof(MyFancyCollection.))] + public class MyFancyCollection : IEnumerable + { + public MyFancyCollection Create(ReadOnlySpan ints) + { + return null; + } + + public IEnumerator GetEnumerator() + { + throw new NotImplementedException(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } + """; + + CreateCompilationWithSpan([source, CollectionBuilderAttributeDefinition]).VerifyEmitDiagnostics( + // (6,72): error CS1001: Identifier expected + // [CollectionBuilder(typeof(MyFancyCollection), nameof(MyFancyCollection.))] + Diagnostic(ErrorCode.ERR_IdentifierExpected, ")").WithLocation(6, 72) + ); + } + + [Fact] + [WorkItem("https://github.com/dotnet/roslyn/issues/81576")] + public void Issue81576_02() + { + var source = """ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Runtime.CompilerServices; + + [CollectionBuilder(typeof(MyFancyCollection), nameof(MyFancyCollection.Missing))] + public class MyFancyCollection : IEnumerable + { + public MyFancyCollection Create(ReadOnlySpan ints) + { + return null; + } + + public IEnumerator GetEnumerator() + { + throw new NotImplementedException(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } + """; + + CreateCompilationWithSpan([source, CollectionBuilderAttributeDefinition]).VerifyEmitDiagnostics( + // (6,72): error CS0117: 'MyFancyCollection' does not contain a definition for 'Missing' + // [CollectionBuilder(typeof(MyFancyCollection), nameof(MyFancyCollection.Missing))] + Diagnostic(ErrorCode.ERR_NoSuchMember, "Missing").WithArguments("MyFancyCollection", "Missing").WithLocation(6, 72) + ); + } + + [Fact] + [WorkItem("https://github.com/dotnet/roslyn/issues/81576")] + public void Issue81576_03() + { + var source = """ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Runtime.CompilerServices; + + [CollectionBuilder(typeof(MyFancyCollection), nameof(MyFancyCollection.Create))] + public class MyFancyCollection : IEnumerable + { + public MyFancyCollection Create(ReadOnlySpan ints) + { + return null; + } + + public IEnumerator GetEnumerator() + { + throw new NotImplementedException(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } + """; + + CreateCompilationWithSpan([source, CollectionBuilderAttributeDefinition]).VerifyEmitDiagnostics(); + } } } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs index 992c884f56c44..7a73e7f95f154 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs @@ -2348,7 +2348,7 @@ class Attr : System.Attribute { public Attr(string s) {} }"; } [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] - public void TestInvalidRecursiveUsageOfNameofInAttributesDoesNotCrashCompiler2() + public void TestInvalidRecursiveUsageOfNameofInAttributesDoesNotCrashCompiler2_01() { var source = @" class C @@ -2365,6 +2365,50 @@ class Attr : System.Attribute { public Attr(string s) {} }"; }; CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics(expectedDiagnostics); CreateCompilation(source, parseOptions: TestOptions.RegularPreview).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics( + // (4,18): error CS0120: An object reference is required for the non-static field, method, or property 'C.Method()' + // [Attr(nameof(Method().Method))] + Diagnostic(ErrorCode.ERR_ObjectRequired, "Method").WithArguments("C.Method()").WithLocation(4, 18) + ); + } + + [Fact] + public void TestInvalidRecursiveUsageOfNameofInAttributesDoesNotCrashCompiler2_02() + { + var source = @" +class C +{ + [Attr(nameof(P.P))] + C P => default; +} +class Attr : System.Attribute { public Attr(string s) {} }"; + CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics(); + CreateCompilation(source, parseOptions: TestOptions.RegularPreview).VerifyDiagnostics(); + CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics( + // (4,18): error CS9058: Feature 'instance member in 'nameof'' is not available in C# 11.0. Please use language version 12.0 or greater. + // [Attr(nameof(P.P))] + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion11, "P").WithArguments("instance member in 'nameof'", "12.0").WithLocation(4, 18) + ); + } + + [Fact] + public void TestInvalidRecursiveUsageOfNameofInAttributesDoesNotCrashCompiler2_03() + { + var source = @" +class C +{ + [Attr(nameof(this.P.P))] + C P => default; +} +class Attr : System.Attribute { public Attr(string s) {} }"; + var expectedDiagnostics = new[] + { + // (4,18): error CS0027: Keyword 'this' is not available in the current context + // [Attr(nameof(this.P.P))] + Diagnostic(ErrorCode.ERR_ThisInBadContext, "this").WithLocation(4, 18) + }; + CreateCompilation(source, parseOptions: TestOptions.Regular12).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(source, parseOptions: TestOptions.RegularPreview).VerifyDiagnostics(expectedDiagnostics); CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics(expectedDiagnostics); }