Skip to content

Commit

Permalink
Code changes to allow 'using static unsafe' (#67344)
Browse files Browse the repository at this point in the history
* Code changes to allow 'using static unsafe'

* Fix xml

* NRT

* Add tests

* Support reversed modifiers

* Simplify

* Report fewer errors

* Report fewer errors

* Fix switch

* Update tests

* Move code down

* Always check flag

* Always check flag

* Update tests

* Update tests

* Fix docs

* Remove docs

* Extract local

* pass flag along

* REmove test
  • Loading branch information
CyrusNajmabadi committed Mar 21, 2023
1 parent 1ef885e commit 35391a8
Show file tree
Hide file tree
Showing 21 changed files with 1,363 additions and 82 deletions.
5 changes: 4 additions & 1 deletion src/Compilers/CSharp/Portable/CSharpResources.resx
Expand Up @@ -6854,7 +6854,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<value>Using alias cannot be a 'ref' type.</value>
</data>
<data name="ERR_BadUnsafeInUsingDirective" xml:space="preserve">
<value>Only a using alias can be 'unsafe'.</value>
<value>Only a 'using static' or 'using alias' can be 'unsafe'.</value>
</data>
<data name="ERR_BadNullableReferenceTypeInUsingAlias" xml:space="preserve">
<value>Using alias cannot be a nullable reference type.</value>
Expand Down Expand Up @@ -7499,6 +7499,9 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<data name="WRN_AddressOfInAsync_Title" xml:space="preserve">
<value>The '&amp;' operator should not be used on parameters or local variables in async methods.</value>
</data>
<data name="ERR_BadStaticAfterUnsafe" xml:space="preserve">
<value>'static' modifier must precede 'unsafe' modifier.</value>
</data>
<data name="ERR_BadCaseInSwitchArm" xml:space="preserve">
<value>A switch expression arm does not begin with a 'case' keyword.</value>
</data>
Expand Down
1 change: 1 addition & 0 deletions src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
Expand Up @@ -2186,6 +2186,7 @@ internal enum ErrorCode
ERR_BadRefInUsingAlias = 9130,
ERR_BadUnsafeInUsingDirective = 9131,
ERR_BadNullableReferenceTypeInUsingAlias = 9132,
ERR_BadStaticAfterUnsafe = 9133,

ERR_BadCaseInSwitchArm = 9134,
#endregion
Expand Down
1 change: 1 addition & 0 deletions src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs
Expand Up @@ -2307,6 +2307,7 @@ internal static bool IsBuildOnlyDiagnostic(ErrorCode code)
case ErrorCode.ERR_BadRefInUsingAlias:
case ErrorCode.ERR_BadUnsafeInUsingDirective:
case ErrorCode.ERR_BadNullableReferenceTypeInUsingAlias:
case ErrorCode.ERR_BadStaticAfterUnsafe:
case ErrorCode.ERR_BadCaseInSwitchArm:
return false;
default:
Expand Down
8 changes: 8 additions & 0 deletions src/Compilers/CSharp/Portable/Parser/LanguageParser.cs
Expand Up @@ -796,6 +796,14 @@ private UsingDirectiveSyntax ParseUsingDirective()
var staticToken = this.TryEatToken(SyntaxKind.StaticKeyword);
var unsafeToken = this.TryEatToken(SyntaxKind.UnsafeKeyword);

// if the user wrote `using unsafe static` skip the `static` and tell them it needs to be `using static unsafe`.
if (staticToken is null && unsafeToken != null && this.CurrentToken.Kind == SyntaxKind.StaticKeyword)
{
// create a missing 'static' token so that later binding does recognize what the user wanted.
staticToken = SyntaxFactory.MissingToken(SyntaxKind.StaticKeyword);
unsafeToken = AddTrailingSkippedSyntax(unsafeToken, AddError(this.EatToken(), ErrorCode.ERR_BadStaticAfterUnsafe));
}

var alias = this.IsNamedAssignment() ? ParseNameEquals() : null;

TypeSyntax type;
Expand Down
Expand Up @@ -721,14 +721,37 @@ private UsingsAndDiagnostics GetUsingsAndDiagnostics(ref UsingsAndDiagnostics? u
continue;
}

var flags = BinderFlags.SuppressConstraintChecks;
if (usingDirective.UnsafeKeyword != default)
diagnostics.Add(ErrorCode.ERR_BadUnsafeInUsingDirective, usingDirective.UnsafeKeyword.GetLocation());
{
var unsafeKeywordLocation = usingDirective.UnsafeKeyword.GetLocation();
if (usingDirective.StaticKeyword == default)
{
diagnostics.Add(ErrorCode.ERR_BadUnsafeInUsingDirective, unsafeKeywordLocation);
}
else
{
MessageID.IDS_FeatureUsingTypeAlias.CheckFeatureAvailability(diagnostics, usingDirective, unsafeKeywordLocation);
declaringSymbol.CheckUnsafeModifier(DeclarationModifiers.Unsafe, unsafeKeywordLocation, diagnostics);
}

flags |= BinderFlags.UnsafeRegion;
}
else
{
// Prior to C#12, allow the using static type to be an unsafe region. This allows us to
// maintain compat with prior versions of the compiler that allowed `using static
// List<int*[]>;` to be written. In 12.0 and onwards though, we require the code to
// explicitly contain the `unsafe` keyword.
if (!compilation.IsFeatureEnabled(MessageID.IDS_FeatureUsingTypeAlias))
flags |= BinderFlags.UnsafeRegion;
}

var directiveDiagnostics = BindingDiagnosticBag.GetInstance();
Debug.Assert(directiveDiagnostics.DiagnosticBag is object);
Debug.Assert(directiveDiagnostics.DependenciesBag is object);

declarationBinder ??= compilation.GetBinderFactory(declarationSyntax.SyntaxTree).GetBinder(usingDirective.NamespaceOrType).WithAdditionalFlags(BinderFlags.SuppressConstraintChecks);
declarationBinder ??= compilation.GetBinderFactory(declarationSyntax.SyntaxTree).GetBinder(usingDirective.NamespaceOrType).WithAdditionalFlags(flags);
var imported = declarationBinder.BindNamespaceOrTypeSymbol(usingDirective.NamespaceOrType, directiveDiagnostics, basesBeingResolved).NamespaceOrTypeSymbol;

if (imported.Kind == SymbolKind.Namespace)
Expand Down
7 changes: 6 additions & 1 deletion src/Compilers/CSharp/Portable/Symbols/SymbolExtensions.cs
Expand Up @@ -293,8 +293,13 @@ internal static void CheckUnsafeModifier(this Symbol symbol, DeclarationModifier
}

internal static void CheckUnsafeModifier(this Symbol symbol, DeclarationModifiers modifiers, Location errorLocation, BindingDiagnosticBag diagnostics)
=> CheckUnsafeModifier(symbol, modifiers, errorLocation, diagnostics.DiagnosticBag);

internal static void CheckUnsafeModifier(this Symbol symbol, DeclarationModifiers modifiers, Location errorLocation, DiagnosticBag? diagnostics)
{
if (((modifiers & DeclarationModifiers.Unsafe) == DeclarationModifiers.Unsafe) && !symbol.CompilationAllowsUnsafe())
if (diagnostics != null &&
(modifiers & DeclarationModifiers.Unsafe) == DeclarationModifiers.Unsafe &&
!symbol.CompilationAllowsUnsafe())
{
RoslynDebug.Assert(errorLocation != null);
diagnostics.Add(ErrorCode.ERR_IllegalUnsafe, errorLocation);
Expand Down
9 changes: 7 additions & 2 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 7 additions & 2 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 7 additions & 2 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 7 additions & 2 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 7 additions & 2 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 7 additions & 2 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 7 additions & 2 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 7 additions & 2 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 7 additions & 2 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 7 additions & 2 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 35391a8

Please sign in to comment.