Merged PR 694738: Migrate to the latest C# compiler that supports C# 11

Migrate to the latest C# compiler that supports C# 11

The PR adds 'RequiredMemberAttribute' to support 'required' members from C# 11.

The latest compiler changed the behavior for '<<' operator making it checked. This PR addresses this by using 'unchecked' in the cases where the overflow is possible.

Related work items: #2017950
This commit is contained in:
Sergey Tepliakov 2022-12-28 19:21:16 +00:00
Родитель cbb440cfd7
Коммит 8e9ba5ac1d
27 изменённых файлов: 183 добавлений и 73 удалений

Просмотреть файл

@ -5,13 +5,9 @@ import {Artifact, Cmd, Tool, Transformer} from "Sdk.Transformers";
import * as Shared from "Sdk.Managed.Shared";
import * as RoslynAnalyzers from "Sdk.Managed.Tools.RoslynAnalyzers";
const pkgContents = Context.getCurrentHost().os === "win"
? importFrom("Microsoft.Net.Compilers").Contents.all
: importFrom("Microsoft.NETCore.Compilers").Contents.all;
const pkgContents = importFrom("Microsoft.Net.Compilers.Toolset").Contents.all;
const cscTool = Context.getCurrentHost().os === "win"
? r`tools/csc.exe`
: r`tools/bincore/csc.dll`;
const cscTool = r`tasks/net6.0/bincore/csc.dll`;
export const tool: Transformer.ToolDefinition = Shared.Factory.createTool({
exe: pkgContents.getFile(cscTool),
@ -190,15 +186,16 @@ export function compile(inputArgs: Arguments) : Result {
// compensate for the unobserved ones.
unsafe: args.shared ?
{
childProcessesToBreakawayFromSandbox: isCurrentHostOsWindows
? [ a`VBCSCompiler.exe` ]
: [ a`dotnet` ],
childProcessesToBreakawayFromSandbox: isCurrentHostOsWindows ? [a`dotnet.exe`] : [a`dotnet`],
trustStaticallyDeclaredAccesses: true,
} : undefined,
};
// Microsoft.Net.Compilers.Toolset contains csc.dll for all platforms.
cscExecuteArgs = importFrom("Sdk.Managed.Frameworks").Helpers.wrapInDotNetExeForCurrentOs(getDotNetCoreVersion(cscExecuteArgs), cscExecuteArgs);
if (!isCurrentHostOsWindows) {
cscExecuteArgs = importFrom("Sdk.Managed.Frameworks").Helpers.wrapInDotNetExeForCurrentOs(getDotNetCoreVersion(cscExecuteArgs), cscExecuteArgs);
cscExecuteArgs = cscExecuteArgs.merge<Transformer.ExecuteArguments>({
tool: {
// Conceptually, we want to set 'dependsOnCurrentHostOSDirectories' to true and not specify 'untrackedDirectoryScopes' here;

Просмотреть файл

@ -463,7 +463,7 @@ export function test(args: TestArguments) : TestResult {
export const notNullAttributesFile = f`NotNullAttributes.cs`;
const callerArgumentExpressionAttributeFile = f`CallerArgumentExpressionAttribute.cs`;
const requiredAttributeFile = f`RequiredAttribute.cs`;
const isExternalInit = f`IsExternalInit.cs`;
/**
@ -848,6 +848,14 @@ function processArguments(args: Arguments, targetType: Csc.TargetType) : Argumen
});
}
// Required members is needed for non .net7 target frameworks.
// Uncomment once the .net7 PR is in.
// if (qualifier.targetFramework !== "net7.0") {
args = args.merge({
sources: [requiredAttributeFile]
});
// }
// Adding 'CallerArgumentExpressionAttribute' unless spcified not to.
if (!isDotNetCoreApp && args.addCallerArgumentExpressionAttribute !== false) {
args = args.merge({

Просмотреть файл

@ -0,0 +1,35 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
// Copied from https://github/dotnet/runtime
#if !NET7_0_OR_GREATER
namespace System.Runtime.CompilerServices;
/// <summary>Specifies that a type has required members or that a member is required.</summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
internal sealed class RequiredMemberAttribute : Attribute { }
/// <summary>
/// Indicates that compiler support for a particular feature is required for the location where this attribute is applied.
/// </summary>
[AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = false)]
internal sealed class CompilerFeatureRequiredAttribute : Attribute
{
public CompilerFeatureRequiredAttribute(string featureName)
{
FeatureName = featureName;
}
/// <summary>
/// The name of the compiler feature.
/// </summary>
public string FeatureName { get; }
/// <summary>
/// If true, the compiler can choose to allow access to the location where this attribute is applied if it does not understand <see cref="FeatureName"/>.
/// </summary>
public bool IsOptional { get; init; }
}
#endif

Просмотреть файл

@ -225,8 +225,11 @@ namespace BuildXL.Cache.ContentStore.Distributed.NuCache
/// </param>
public Result<MachineId[]> GetDesignatedLocations(ContentHash hash, bool includeExpired)
{
uint binNumber = (uint)((hash[0] | hash[1] << 8) % NumberOfBins);
return GetDesignatedLocations(binNumber, includeExpired);
unchecked
{
uint binNumber = (uint)((hash[0] | hash[1] << 8) % NumberOfBins);
return GetDesignatedLocations(binNumber, includeExpired);
}
}
/// <nodoc />

Просмотреть файл

@ -163,7 +163,13 @@ namespace BuildXL.Cache.ContentStore.Distributed.NuCache
yield return new MachineId(((i - Offset) * 8) + position);
}
@char <<= 1;
// C# 11 compiler makes the '<<' operator checked potentially causing OverflowException
// if @char will get above byte.MaxValue.
unchecked
{
@char <<= 1;
}
position++;
}
}
@ -206,7 +212,13 @@ namespace BuildXL.Cache.ContentStore.Distributed.NuCache
machineIdIndex++;
}
redisChar <<= 1;
// C# 11 compiler makes the '<<' operator checked potentially causing OverflowException
// if @char will get above byte.MaxValue.
unchecked
{
redisChar <<= 1;
}
position++;
}
@ -225,7 +237,10 @@ namespace BuildXL.Cache.ContentStore.Distributed.NuCache
// The bit mask uses the most significant bits to specify lower machine ids.
// It means that 0b10000010 is translated into machines 0 and 6, but not 1 and 7.
return (data[dataIndex] & (1 << (7 - (index % 8)))) != 0;
unchecked
{
return (data[dataIndex] & (1 << (7 - (index % 8)))) != 0;
}
}
private static void SetValue(byte[] data, int offset, int index, bool value)

Просмотреть файл

@ -103,9 +103,12 @@ namespace BuildXL.Cache.ContentStore.Distributed.NuCache
partitionCount = Math.Min(Math.Max(minValue, partitionCount), maxValue);
// Round to power of two
var powerOfTwo = Bits.HighestBitSet((uint)partitionCount);
partitionCount = (int)(powerOfTwo < partitionCount ? powerOfTwo << 1 : powerOfTwo);
return partitionCount;
unchecked
{
var powerOfTwo = Bits.HighestBitSet((uint)partitionCount);
partitionCount = (int)(powerOfTwo < partitionCount ? powerOfTwo << 1 : powerOfTwo);
return partitionCount;
}
}
}
}

Просмотреть файл

@ -211,7 +211,11 @@ namespace BuildXL.Cache.ContentStore.Hashing
{
int bitShift = 8 * i;
ulong b = br.ReadByte();
b <<= bitShift;
unchecked
{
b <<= bitShift;
}
value |= b;
}

Просмотреть файл

@ -9,16 +9,16 @@ namespace BuildXL.Cache.ContentStore.Interfaces.FileSystem
/// Information about a file.
/// </summary>
[SuppressMessage("Microsoft.Performance", "CA1815:OverrideEqualsAndOperatorEqualsOnValueTypes")]
public struct FileInfo
public readonly struct FileInfo
{
/// <summary>
/// Full path to the file.
/// </summary>
public AbsolutePath FullPath;
public required AbsolutePath FullPath { get; init; }
/// <summary>
/// Size of the file in bytes.
/// </summary>
public long Length;
public required long Length { get; init; }
}
}

Просмотреть файл

@ -111,7 +111,7 @@ namespace BuildXL.Cache.ContentStore.InterfacesTest.Hashing
Assert.Equal(v1, v2);
}
private ReadOnlySpan<byte> ToSpan(ReadOnlyFixedBytes fixedBytes)
private ReadOnlySpan<byte> ToSpan(in ReadOnlyFixedBytes fixedBytes)
{
#if NETCOREAPP
return MemoryHelpers.AsBytesUnsafe(fixedBytes);

Просмотреть файл

@ -191,7 +191,10 @@ namespace BuildXL.Cache.ContentStore.FileSystem
throw ThrowLastWin32Error(path.Path, errorMessage);
}
return (((ulong)handleInfo.FileIndexHigh) << 32) | handleInfo.FileIndexLow;
unchecked
{
return (((ulong)handleInfo.FileIndexHigh) << 32) | handleInfo.FileIndexLow;
}
}
}
}

Просмотреть файл

@ -99,7 +99,10 @@ namespace BuildXL.Cache.ContentStore.Service
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int DeserializeInt32()
{
return _buffer[_offset++] | (_buffer[_offset++] << 8) | (_buffer[_offset++] << 16) | (_buffer[_offset++] << 24);
unchecked
{
return _buffer[_offset++] | (_buffer[_offset++] << 8) | (_buffer[_offset++] << 16) | (_buffer[_offset++] << 24);
}
}
/// <summary>
@ -126,15 +129,18 @@ namespace BuildXL.Cache.ContentStore.Service
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public long DeserializeInt64()
{
return
_buffer[_offset++] |
(long)_buffer[_offset++] << 8 |
(long)_buffer[_offset++] << 16 |
(long)_buffer[_offset++] << 24 |
(long)_buffer[_offset++] << 32 |
(long)_buffer[_offset++] << 40 |
(long)_buffer[_offset++] << 48 |
(long)_buffer[_offset++] << 56;
unchecked
{
return
_buffer[_offset++] |
(long)_buffer[_offset++] << 8 |
(long)_buffer[_offset++] << 16 |
(long)_buffer[_offset++] << 24 |
(long)_buffer[_offset++] << 32 |
(long)_buffer[_offset++] << 40 |
(long)_buffer[_offset++] << 48 |
(long)_buffer[_offset++] << 56;
}
}
/// <summary>

Просмотреть файл

@ -276,7 +276,10 @@ namespace BuildXL.Cache.ContentStore.Stores
for (var i = 0; i < Math.Min(value.Length, sizeof(long)); i++)
{
output |= ((long)value[i]) << (8 * i);
unchecked
{
output |= ((long)value[i]) << (8 * i);
}
}
return output;
}

Просмотреть файл

@ -145,7 +145,10 @@ namespace BuildXL.FrontEnd.Script.Expressions
Converter.ExpectNumber(value, position: 1), LocationForLogging(context, env));
break;
case AssignmentOperator.LeftShiftAssignment:
frame[Index] = NumberLiteral.Box(Converter.ExpectNumber(frame[Index], position: 0) << Converter.ExpectNumber(value, position: 1));
unchecked
{
frame[Index] = NumberLiteral.Box(Converter.ExpectNumber(frame[Index], position: 0) << Converter.ExpectNumber(value, position: 1));
}
break;
case AssignmentOperator.RightShiftAssignment:
frame[Index] = NumberLiteral.Box(NumberOperations.SignPropagatingRightShift(

Просмотреть файл

@ -201,7 +201,10 @@ namespace BuildXL.FrontEnd.Script.Expressions
break;
case BinaryOperator.LeftShift:
return EvaluationResult.Create(Converter.ExpectNumber(left, position: 0) << Converter.ExpectNumber(right, position: 1));
unchecked
{
return EvaluationResult.Create(Converter.ExpectNumber(left, position: 0) << Converter.ExpectNumber(right, position: 1));
}
case BinaryOperator.SignPropagatingRightShift:
return EvaluationResult.Create(NumberOperations.SignPropagatingRightShift(
Converter.ExpectNumber(left, position: 0),

Просмотреть файл

@ -86,8 +86,10 @@ namespace BuildXL.FrontEnd.Script.RuntimeModel.AstBridge
return Script.Core.NumberOperations.SignPropagatingRightShift(left.Value, right.Value);
case TypeScript.Net.Types.SyntaxKind.LessThanLessThanToken:
return GetNumber(left) << GetNumber(right);
unchecked
{
return GetNumber(left) << GetNumber(right);
}
case TypeScript.Net.Types.SyntaxKind.AsteriskToken:
return GetNumber(left) * GetNumber(right);
case TypeScript.Net.Types.SyntaxKind.SlashToken:

Просмотреть файл

@ -83,7 +83,10 @@ namespace TypeScript.Net.Types
/// <nodoc />
public static Number operator <<(Number left, int right)
{
return new Number(left.AsInt64() << right);
unchecked
{
return new Number(left.AsInt64() << right);
}
}
/// <nodoc />

Просмотреть файл

@ -85,7 +85,10 @@ namespace BuildXL.Utilities
Contract.Requires(((byte)fileExistence) <= MaxFileExistence);
m_path = path;
m_rewriteCountAndFileExistenceAndFileRewrite = ((uint)rewriteCount | (uint)((byte)fileExistence << RewriteCountSize) | (isUndeclaredFileRewrite ? UndeclaredFileRewriteMask : 0));
unchecked
{
m_rewriteCountAndFileExistenceAndFileRewrite = ((uint)rewriteCount | (uint)((byte)fileExistence << RewriteCountSize) | (isUndeclaredFileRewrite ? UndeclaredFileRewriteMask : 0));
}
}
/// <summary>

Просмотреть файл

@ -369,11 +369,14 @@ namespace BuildXL.Utilities
{
// HashCodeHelper performs a stable hash code computation.
// We take into account the other header fields, and the file length.
return HashCodeHelper.Combine(
HashCodeHelper.GetOrdinalHashCode64(m_name),
HashCodeHelper.GetOrdinalHashCode64(id.Value),
Version | (long)(((ulong)(uint)m_version) << 32),
length);
unchecked
{
return HashCodeHelper.Combine(
HashCodeHelper.GetOrdinalHashCode64(m_name),
HashCodeHelper.GetOrdinalHashCode64(id.Value),
Version | (long)(((ulong)(uint)m_version) << 32),
length);
}
}
/// <summary>

Просмотреть файл

@ -1291,7 +1291,7 @@ namespace BuildXL.Utilities
// The null node has a special owner-less ID (and we don't allow flags on it). Don't add an owner tag or equality would break.
return index == 0
? new HierarchicalNameId(0)
: new HierarchicalNameId(index | (DebugTag << DebugTagShift));
: new HierarchicalNameId(unchecked(index | (DebugTag << DebugTagShift)));
}
private static int GetIndexFromId(HierarchicalNameId id)
@ -1387,7 +1387,7 @@ namespace BuildXL.Utilities
Contract.Assert((int)flags > 0 && (int)flags <= DebugTagValueMask);
int shiftedFlags = (int)flags << DebugTagShift;
int shiftedFlags = unchecked((int)flags << DebugTagShift);
int nodeIndex = GetIndexFromId(name);
m_nodes.GetEntryBuffer(nodeIndex, out int index, out Node[] buffer);
@ -1446,7 +1446,7 @@ namespace BuildXL.Utilities
Contract.Assert((int)flags > 0 && (int)flags <= DebugTagValueMask);
int shiftedFlags = (int)flags << DebugTagShift;
int shiftedFlags = unchecked((int)flags << DebugTagShift);
int nodeIndex = GetIndexFromId(name);
m_nodes.GetEntryBuffer(nodeIndex, out int index, out Node[] buffer);

Просмотреть файл

@ -3,6 +3,7 @@
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
#nullable enable
@ -85,7 +86,17 @@ namespace BuildXL.Utilities.Serialization
Position += length;
return result;
}
/// <nodoc />
public ReadOnlySpan<T> Read<T>(int count)
where T : unmanaged
{
// Reading a span instead of reading bytes to avoid unnecessary allocations.
var itemSpan = ReadSpan(Unsafe.SizeOf<T>() * count);
var result = MemoryMarshal.Cast<byte, T>(itemSpan);
return result;
}
internal void EnsureLength(int minLength)
{
if (RemainingLength < minLength)

Просмотреть файл

@ -143,7 +143,10 @@ namespace BuildXL.Utilities.Serialization
{
// ReadByte handles end of stream cases for us.
byteReadJustNow = reader.ReadByte();
result |= (byteReadJustNow & 0x7Fu) << shift;
unchecked
{
result |= (byteReadJustNow & 0x7Fu) << shift;
}
if (byteReadJustNow <= 0x7Fu)
{
@ -240,16 +243,6 @@ namespace BuildXL.Utilities.Serialization
return result;
}
/// <nodoc />
public static ReadOnlySpan<T> Read<T>(this ref SpanReader reader, int count)
where T : unmanaged
{
// Reading a span instead of reading bytes to avoid unnecessary allocations.
var itemSpan = reader.ReadSpan(Unsafe.SizeOf<T>() * count);
var result = MemoryMarshal.Cast<byte, T>(itemSpan);
return result;
}
/// <nodoc />
public static void Write(this ref SpanWriter writer, byte value) => writer.WriteByte(value); // Using a special overload instead of using a generic method for performance reasons

Просмотреть файл

@ -124,7 +124,7 @@ namespace BuildXL.Utilities
int end = m_index + Length;
for (int i = m_index; i < end; i++)
{
var storedCh = (char)((buffer[index++] << 8) | buffer[index++]);
var storedCh = unchecked((char)((buffer[index++] << 8) | buffer[index++]));
if (storedCh != m_value[i])
{
return false;

Просмотреть файл

@ -147,7 +147,7 @@ namespace BuildXL.Utilities
int end = m_index + Length;
for (int i = m_index; i < end; i++)
{
var storedCh = (char)((buffer[index++] << 8) | buffer[index++]);
var storedCh = unchecked((char)((buffer[index++] << 8) | buffer[index++]));
if (storedCh != m_value[i])
{
return false;

Просмотреть файл

@ -358,8 +358,8 @@ namespace BuildXL.Utilities
index2++; // skip the marker
for (int i = 0; i < length1; i++)
{
var ch1 = (char)((buffer1[index1 + (2 * i)] << 8) | buffer1[index1 + (2 * i) + 1]);
var ch2 = (char)((buffer2[index2 + (2 * i)] << 8) | buffer2[index2 + (2 * i) + 1]);
var ch1 = unchecked((char)((buffer1[index1 + (2 * i)] << 8) | buffer1[index1 + (2 * i) + 1]));
var ch2 = unchecked((char)((buffer2[index2 + (2 * i)] << 8) | buffer2[index2 + (2 * i) + 1]));
if (ch1.ToUpperInvariantFast() != ch2.ToUpperInvariantFast())
{
return false;
@ -491,7 +491,7 @@ namespace BuildXL.Utilities
index++; // skip the marker
while (length-- > 0)
{
var ch = (char)((buffer[index++] << 8) | buffer[index++]);
var ch = unchecked((char)((buffer[index++] << 8) | buffer[index++]));
ch = ch.ToUpperInvariantFast();
unchecked
{
@ -606,7 +606,7 @@ namespace BuildXL.Utilities
if (space < BytesPerBuffer - byteIndex)
{
// there's room in the buffer so try to claim it
int next = (bufferNum << BytesPerBufferBits) | (byteIndex + space);
int next = unchecked((bufferNum << BytesPerBufferBits) | (byteIndex + space));
if (Interlocked.CompareExchange(ref m_nextId, next, current) == current)
{
// got some room, now go fill it in
@ -671,12 +671,12 @@ namespace BuildXL.Utilities
if (space >= BytesPerBuffer)
{
// force writing into a fresh buffer
Volatile.Write(ref m_nextId, (bufferNum << BytesPerBufferBits) | BytesPerBufferMask);
Volatile.Write(ref m_nextId, unchecked((bufferNum << BytesPerBufferBits) | BytesPerBufferMask));
}
else
{
// force writing into this new buffer
Volatile.Write(ref m_nextId, (bufferNum << BytesPerBufferBits) | space);
Volatile.Write(ref m_nextId, unchecked((bufferNum << BytesPerBufferBits) | space));
}
// go write the string at the base of the new buffer
@ -808,7 +808,7 @@ namespace BuildXL.Utilities
index++; // skip the marker
while (length-- > 0)
{
destination[destinationIndex++] = (char)((buffer[index++] << 8) | buffer[index++]);
destination[destinationIndex++] = unchecked((char)((buffer[index++] << 8) | buffer[index++]));
}
}
@ -844,7 +844,7 @@ namespace BuildXL.Utilities
index++; // skip the marker
while (length-- > 0)
{
destination.Append((char)((buffer[index++] << 8) | buffer[index++]));
destination.Append(unchecked((char)((buffer[index++] << 8) | buffer[index++])));
}
}
}

Просмотреть файл

@ -18,7 +18,7 @@ if NOT DEFINED DBD_TESTGEN_COUNT (
)
if NOT DEFINED TEST_COMMITID (
set TEST_COMMITID=9f28a24a2aee8196187349a9e9bc9d6d60c6c901
set TEST_COMMITID=e011e12fdabc0011eacd2e9dad95ce0e108c5b8c
)
set TEST_SOLUTION_ROOT=%ENLISTMENTROOT%\Out\Tests\SMDB

Просмотреть файл

@ -1963,6 +1963,15 @@
}
}
},
{
"Component": {
"Type": "NuGet",
"NuGet": {
"Name": "Microsoft.Net.Compilers.Toolset",
"Version": "4.4.0"
}
}
},
{
"Component": {
"Type": "NuGet",

Просмотреть файл

@ -90,8 +90,11 @@ config({
{ id: "System.Diagnostics.DiagnosticSource", version: "4.0.0-beta-23516", alias: "System.Diagnostics.DiagnosticsSource.ForEventHub"},
// Roslyn
// The old compiler used by integration tests only.
{ id: "Microsoft.Net.Compilers", version: "4.0.1" }, // Update Public/Src/Engine/UnitTests/Engine/Test.BuildXL.Engine.dsc if you change the version of Microsoft.Net.Compilers.
{ id: "Microsoft.NETCore.Compilers", version: "4.0.1" },
// The package with an actual csc.dll
{ id: "Microsoft.Net.Compilers.Toolset", version: "4.4.0" },
{ id: "Microsoft.CodeAnalysis.Common", version: "3.5.0" },
{ id: "Microsoft.CodeAnalysis.CSharp", version: "3.5.0" },