未验证 提交 fae142c1 编写于 作者: M msftbot[bot] 提交者: GitHub

Merge pull request #40147 from dotnet/merges/master-to-master-vs-deps

Merge master to master-vs-deps
......@@ -3,9 +3,9 @@
<ProductDependencies>
</ProductDependencies>
<ToolsetDependencies>
<Dependency Name="Microsoft.DotNet.Arcade.Sdk" Version="5.0.0-beta.19602.4">
<Dependency Name="Microsoft.DotNet.Arcade.Sdk" Version="5.0.0-beta.19603.17">
<Uri>https://github.com/dotnet/arcade</Uri>
<Sha>9d34fd008e754e1ada35c8b6bc3694e7a90b4ed7</Sha>
<Sha>b902fd6b6948e689a5128fa6d94dc7de13e6af84</Sha>
</Dependency>
</ToolsetDependencies>
</Dependencies>
......@@ -16,7 +16,7 @@
# condition: eq(variables['Agent.OS'], 'Windows_NT')
# inputs:
# filePath: $(Build.SourcesDirectory)/eng/common/SetupNugetSources.ps1
# arguments: -ConfigFile ${Env:BUILD_SOURCESDIRECTORY}/NuGet.config -Password $Env:Token
# arguments: -ConfigFile $(Build.SourcesDirectory)/NuGet.config -Password $Env:Token
# env:
# Token: $(dn-bot-dnceng-artifact-feeds-rw)
......@@ -94,41 +94,48 @@ function InsertMaestroPrivateFeedCredentials($Sources, $Creds, $Password) {
}
}
try {
if (!(Test-Path $ConfigFile -PathType Leaf)) {
Write-PipelineTelemetryError -Category 'Build' -Message "Couldn't find the file NuGet config file: $ConfigFile"
if (!(Test-Path $ConfigFile -PathType Leaf)) {
Write-PipelineTelemetryError -Category 'Build' -Message "Eng/common/SetupNugetSources.ps1 returned a non-zero exit code. Couldn't find the NuGet config file: $ConfigFile"
ExitWithExitCode 1
}
if (!$Password) {
Write-PipelineTelemetryError -Category 'Build' -Message 'Eng/common/SetupNugetSources.ps1 returned a non-zero exit code. Please supply a valid PAT'
ExitWithExitCode 1
}
}
# Load NuGet.config
$doc = New-Object System.Xml.XmlDocument
$filename = (Get-Item $ConfigFile).FullName
$doc.Load($filename)
# Load NuGet.config
$doc = New-Object System.Xml.XmlDocument
$filename = (Get-Item $ConfigFile).FullName
$doc.Load($filename)
# Get reference to <PackageSources> or create one if none exist already
$sources = $doc.DocumentElement.SelectSingleNode("packageSources")
if ($sources -eq $null) {
$sources = $doc.CreateElement("packageSources")
$doc.DocumentElement.AppendChild($sources) | Out-Null
}
# Get reference to <PackageSources> or create one if none exist already
$sources = $doc.DocumentElement.SelectSingleNode("packageSources")
if ($sources -eq $null) {
$sources = $doc.CreateElement("packageSources")
$doc.DocumentElement.AppendChild($sources) | Out-Null
}
# Looks for a <PackageSourceCredentials> node. Create it if none is found.
$creds = $doc.DocumentElement.SelectSingleNode("packageSourceCredentials")
if ($creds -eq $null) {
$creds = $doc.CreateElement("packageSourceCredentials")
$doc.DocumentElement.AppendChild($creds) | Out-Null
}
# Looks for a <PackageSourceCredentials> node. Create it if none is found.
$creds = $doc.DocumentElement.SelectSingleNode("packageSourceCredentials")
if ($creds -eq $null) {
$creds = $doc.CreateElement("packageSourceCredentials")
$doc.DocumentElement.AppendChild($creds) | Out-Null
}
# Insert credential nodes for Maestro's private feeds
InsertMaestroPrivateFeedCredentials -Sources $sources -Creds $creds -Password $Password
# Insert credential nodes for Maestro's private feeds
InsertMaestroPrivateFeedCredentials -Sources $sources -Creds $creds -Password $Password
$dotnet3Source = $sources.SelectSingleNode("add[@key='dotnet3']")
if ($dotnet3Source -ne $null) {
AddPackageSource -Sources $sources -SourceName "dotnet3-internal" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3-internal/nuget/v2" -Creds $creds -Username "dn-bot" -Password $Password
AddPackageSource -Sources $sources -SourceName "dotnet3-internal-transport" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3-internal-transport/nuget/v2" -Creds $creds -Username "dn-bot" -Password $Password
$doc.Save($filename)
}
catch {
Write-Host $_.ScriptStackTrace
Write-PipelineTelemetryError -Category 'InitializeToolset' -Message $_
ExitWithExitCode 1
$dotnet31Source = $sources.SelectSingleNode("add[@key='dotnet3.1']")
if ($dotnet31Source -ne $null) {
AddPackageSource -Sources $sources -SourceName "dotnet3.1-internal" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3.1-internal/nuget/v2" -Creds $creds -Username "dn-bot" -Password $Password
AddPackageSource -Sources $sources -SourceName "dotnet3.1-internal-transport" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3.1-internal-transport/nuget/v2" -Creds $creds -Username "dn-bot" -Password $Password
}
$doc.Save($filename)
......@@ -17,7 +17,7 @@
# displayName: Setup Private Feeds Credentials
# inputs:
# filePath: $(Build.SourcesDirectory)/eng/common/SetupNugetSources.sh
# arguments: $BUILD_SOURCESDIRECTORY/NuGet.config $Token
# arguments: $(Build.SourcesDirectory)/NuGet.config $Token
# condition: ne(variables['Agent.OS'], 'Windows_NT')
# env:
# Token: $(dn-bot-dnceng-artifact-feeds-rw)
......@@ -42,7 +42,12 @@ scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
. "$scriptroot/tools.sh"
if [ ! -f "$ConfigFile" ]; then
Write-PipelineTelemetryError -Category 'Build' -Message "Couldn't find the file NuGet config file: $ConfigFile"
Write-PipelineTelemetryError -Category 'Build' "Error: Eng/common/SetupNugetSources.sh returned a non-zero exit code. Couldn't find the NuGet config file: $ConfigFile"
ExitWithExitCode 1
fi
if [ -z "$CredToken" ]; then
Write-PipelineTelemetryError -category 'Build' "Error: Eng/common/SetupNugetSources.sh returned a non-zero exit code. Please supply a valid PAT"
ExitWithExitCode 1
fi
......@@ -52,7 +57,7 @@ if [[ `uname -s` == "Darwin" ]]; then
fi
# Ensure there is a <packageSources>...</packageSources> section.
grep -i "<packageSources>" $ConfigFile
grep -i "<packageSources>" $ConfigFile
if [ "$?" != "0" ]; then
echo "Adding <packageSources>...</packageSources> section."
ConfigNodeHeader="<configuration>"
......@@ -62,7 +67,7 @@ if [ "$?" != "0" ]; then
fi
# Ensure there is a <packageSourceCredentials>...</packageSourceCredentials> section.
grep -i "<packageSourceCredentials>" $ConfigFile
grep -i "<packageSourceCredentials>" $ConfigFile
if [ "$?" != "0" ]; then
echo "Adding <packageSourceCredentials>...</packageSourceCredentials> section."
......@@ -72,37 +77,64 @@ if [ "$?" != "0" ]; then
sed -i.bak "s|$PackageSourcesNodeFooter|$PackageSourcesNodeFooter${NL}$PackageSourceCredentialsTemplate|" NuGet.config
fi
# Ensure dotnet3-internal and dotnet3-internal-transport is in the packageSources
grep -i "<add key=\"dotnet3-internal\">" $ConfigFile
if [ "$?" != "0" ]; then
echo "Adding dotnet3-internal to the packageSources."
PackageSources=()
PackageSourcesNodeFooter="</packageSources>"
PackageSourceTemplate="${TB}<add key=\"dotnet3-internal\" value=\"https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3-internal/nuget/v2\" />"
# Ensure dotnet3-internal and dotnet3-internal-transport are in the packageSources if the public dotnet3 feeds are present
grep -i "<add key=\"dotnet3\"" $ConfigFile
if [ "$?" == "0" ]; then
grep -i "<add key=\"dotnet3-internal\">" $ConfigFile
if [ "$?" != "0" ]; then
echo "Adding dotnet3-internal to the packageSources."
PackageSourcesNodeFooter="</packageSources>"
PackageSourceTemplate="${TB}<add key=\"dotnet3-internal\" value=\"https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3-internal/nuget/v2\" />"
sed -i.bak "s|$PackageSourcesNodeFooter|$PackageSourceTemplate${NL}$PackageSourcesNodeFooter|" $ConfigFile
fi
PackageSources+=('dotnet3-internal')
grep -i "<add key=\"dotnet3-internal-transport\"" $ConfigFile
if [ "$?" != "0" ]; then
echo "Adding dotnet3-internal-transport to the packageSources."
PackageSourcesNodeFooter="</packageSources>"
PackageSourceTemplate="${TB}<add key=\"dotnet3-internal-transport\" value=\"https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3-internal-transport/nuget/v2\" />"
sed -i.bak "s|$PackageSourcesNodeFooter|$PackageSourceTemplate${NL}$PackageSourcesNodeFooter|" NuGet.config
sed -i.bak "s|$PackageSourcesNodeFooter|$PackageSourceTemplate${NL}$PackageSourcesNodeFooter|" $ConfigFile
fi
PackageSources+=('dotnet3-internal-transport')
fi
# Ensure dotnet3-internal and dotnet3-internal-transport is in the packageSources
grep -i "<add key=\"dotnet3-internal-transport\">" $ConfigFile
if [ "$?" != "0" ]; then
echo "Adding dotnet3-internal-transport to the packageSources."
# Ensure dotnet3.1-internal and dotnet3.1-internal-transport are in the packageSources if the public dotnet3.1 feeds are present
grep -i "<add key=\"dotnet3.1\"" $ConfigFile
if [ "$?" == "0" ]; then
grep -i "<add key=\"dotnet3.1-internal\"" $ConfigFile
if [ "$?" != "0" ]; then
echo "Adding dotnet3.1-internal to the packageSources."
PackageSourcesNodeFooter="</packageSources>"
PackageSourceTemplate="${TB}<add key=\"dotnet3.1-internal\" value=\"https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3.1-internal/nuget/v2\" />"
PackageSourcesNodeFooter="</packageSources>"
PackageSourceTemplate="${TB}<add key=\"dotnet3-internal-transport\" value=\"https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3-internal-transport/nuget/v2\" />"
sed -i.bak "s|$PackageSourcesNodeFooter|$PackageSourceTemplate${NL}$PackageSourcesNodeFooter|" $ConfigFile
fi
PackageSources+=('dotnet3.1-internal')
grep -i "<add key=\"dotnet3.1-internal-transport\">" $ConfigFile
if [ "$?" != "0" ]; then
echo "Adding dotnet3.1-internal-transport to the packageSources."
PackageSourcesNodeFooter="</packageSources>"
PackageSourceTemplate="${TB}<add key=\"dotnet3.1-internal-transport\" value=\"https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3.1-internal-transport/nuget/v2\" />"
sed -i.bak "s|$PackageSourcesNodeFooter|$PackageSourceTemplate${NL}$PackageSourcesNodeFooter|" NuGet.config
sed -i.bak "s|$PackageSourcesNodeFooter|$PackageSourceTemplate${NL}$PackageSourcesNodeFooter|" $ConfigFile
fi
PackageSources+=('dotnet3.1-internal-transport')
fi
# I want things split line by line
PrevIFS=$IFS
IFS=$'\n'
PackageSources=$(grep -oh '"darc-int-[^"]*"' $ConfigFile | tr -d '"')
PackageSources+="$IFS"
PackageSources+=$(grep -oh '"darc-int-[^"]*"' $ConfigFile | tr -d '"')
IFS=$PrevIFS
PackageSources+=('dotnet3-internal')
PackageSources+=('dotnet3-internal-transport')
for FeedName in ${PackageSources[@]} ; do
# Check if there is no existing credential for this FeedName
grep -i "<$FeedName>" $ConfigFile
......@@ -112,6 +144,6 @@ for FeedName in ${PackageSources[@]} ; do
PackageSourceCredentialsNodeFooter="</packageSourceCredentials>"
NewCredential="${TB}${TB}<$FeedName>${NL}<add key=\"Username\" value=\"dn-bot\" />${NL}<add key=\"ClearTextPassword\" value=\"$CredToken\" />${NL}</$FeedName>"
sed -i.bak "s|$PackageSourceCredentialsNodeFooter|$NewCredential${NL}$PackageSourceCredentialsNodeFooter|" NuGet.config
sed -i.bak "s|$PackageSourceCredentialsNodeFooter|$NewCredential${NL}$PackageSourceCredentialsNodeFooter|" $ConfigFile
fi
done
......@@ -62,6 +62,8 @@ function Print-Usage() {
Write-Host "The above arguments can be shortened as much as to be unambiguous (e.g. -co for configuration, -t for test, etc.)."
}
. $PSScriptRoot\tools.ps1
function InitializeCustomToolset {
if (-not $restore) {
return
......@@ -113,8 +115,6 @@ function Build {
}
try {
. $PSScriptRoot\tools.ps1
if ($clean) {
if (Test-Path $ArtifactsDir) {
Remove-Item -Recurse -Force $ArtifactsDir
......@@ -122,12 +122,7 @@ try {
}
exit 0
}
if ((Test-Path variable:LastExitCode) -And ($LastExitCode -ne 0)) {
Write-PipelineTelemetryError -Category 'InitializeToolset' -Message 'Eng/common/tools.ps1 returned a non-zero exit code.'
ExitWithExitCode $LastExitCode
}
if ($help -or (($null -ne $properties) -and ($properties.Contains('/help') -or $properties.Contains('/?')))) {
Print-Usage
exit 0
......
......@@ -113,14 +113,16 @@ try {
}
$toolInstallationFailure = $true
} else {
Write-PipelineTelemetryError -Category 'NativeToolsBootstrap' -Message $errMsg
# We cannot change this to Write-PipelineTelemetryError because of https://github.com/dotnet/arcade/issues/4482
Write-Host $errMsg
exit 1
}
}
}
if ((Get-Variable 'toolInstallationFailure' -ErrorAction 'SilentlyContinue') -and $toolInstallationFailure) {
Write-PipelineTelemetryError -Category 'NativeToolsBootstrap' -Message 'Native tools bootstrap failed'
# We cannot change this to Write-PipelineTelemetryError because of https://github.com/dotnet/arcade/issues/4482
Write-Host 'Native tools bootstrap failed'
exit 1
}
}
......
......@@ -105,7 +105,7 @@ try {
Write-Error "There are multiple copies of $ToolName in $($ToolInstallDirectory): `n$(@($ToolFilePath | out-string))"
exit 1
} elseif (@($ToolFilePath).Length -Lt 1) {
Write-Error "$ToolName was not found in $ToolFilePath."
Write-Host "$ToolName was not found in $ToolFilePath."
exit 1
}
......
......@@ -85,7 +85,7 @@ function Write-PipelineTaskError {
[switch]$AsOutput,
[bool]$IsMultiJobVariable=$true)
if(-Not (Test-Path variable:ci) -Or !$ci) {
if((Test-Path variable:ci) -And $ci) {
Write-LoggingCommand -Area 'task' -Event 'setvariable' -Data $Value -Properties @{
'variable' = $Name
'isSecret' = $Secret
......
......@@ -7,6 +7,6 @@
"xcopy-msbuild": "16.3.0-alpha"
},
"msbuild-sdks": {
"Microsoft.DotNet.Arcade.Sdk": "5.0.0-beta.19602.4"
"Microsoft.DotNet.Arcade.Sdk": "5.0.0-beta.19603.17"
}
}
......@@ -78,6 +78,8 @@ private BoundExpression BindCompoundAssignment(AssignmentExpressionSyntax node,
Error(diagnostics, ErrorCode.ERR_BadBinaryOps, node, node.OperatorToken.Text, left.Display, right.Display);
// error: operator can't be applied on dynamic and a type that is not convertible to dynamic:
left = BindToTypeForErrorRecovery(left);
right = BindToTypeForErrorRecovery(right);
return new BoundCompoundAssignmentOperator(node, BinaryOperatorSignature.Error, left, right,
Conversion.NoConversion, Conversion.NoConversion, LookupResultKind.Empty, CreateErrorType(), hasErrors: true);
}
......@@ -90,6 +92,8 @@ private BoundExpression BindCompoundAssignment(AssignmentExpressionSyntax node,
// be used here.
// NOTE: no overload resolution candidates.
left = BindToTypeForErrorRecovery(left);
right = BindToTypeForErrorRecovery(right);
return new BoundCompoundAssignmentOperator(node, BinaryOperatorSignature.Error, left, right,
Conversion.NoConversion, Conversion.NoConversion, LookupResultKind.NotAVariable, CreateErrorType(), hasErrors: true);
}
......
......@@ -1865,14 +1865,14 @@ public override BoundNode VisitObjectCreationExpression(BoundObjectCreationExpre
if (initializerOpt != null)
{
VisitObjectCreationInitializer(null, slot, initializerOpt);
VisitObjectCreationInitializer(containingSymbol: null, slot, initializerOpt, leftAnnotations: FlowAnalysisAnnotations.None);
}
SetResultType(node, TypeWithState.Create(type, resultState));
}
#nullable restore
private void VisitObjectCreationInitializer(Symbol containingSymbol, int containingSlot, BoundExpression node)
private void VisitObjectCreationInitializer(Symbol containingSymbol, int containingSlot, BoundExpression node, FlowAnalysisAnnotations leftAnnotations)
{
TakeIncrementalSnapshot(node);
switch (node)
......@@ -1913,7 +1913,7 @@ private void VisitObjectCreationInitializer(Symbol containingSymbol, int contain
Debug.Assert((object)containingSymbol != null);
if ((object)containingSymbol != null)
{
var type = containingSymbol.GetTypeOrReturnType();
var type = ApplyLValueAnnotations(containingSymbol.GetTypeOrReturnType(), leftAnnotations);
TypeWithState resultType = VisitOptionalImplicitConversion(node, type, useLegacyWarnings: false, trackMembers: true, AssignmentKind.Assignment);
TrackNullableStateForAssignment(node, type, containingSlot, resultType, MakeSlot(node));
}
......@@ -1951,7 +1951,7 @@ private void VisitObjectElementInitializer(int containingSlot, BoundAssignmentOp
if ((object)symbol != null)
{
int slot = (containingSlot < 0) ? -1 : GetOrCreateSlot(symbol, containingSlot);
VisitObjectCreationInitializer(symbol, slot, node.Right);
VisitObjectCreationInitializer(symbol, slot, node.Right, GetLValueAnnotations(node.Left));
// https://github.com/dotnet/roslyn/issues/35040: Should likely be setting _resultType in VisitObjectCreationInitializer
// and using that value instead of reconstructing here
}
......@@ -6010,6 +6010,8 @@ private FlowAnalysisAnnotations GetLValueAnnotations(BoundExpression expr)
BoundPropertyAccess property => getSetterAnnotations(property.PropertySymbol),
BoundIndexerAccess indexer => getSetterAnnotations(indexer.Indexer),
BoundFieldAccess field => getFieldAnnotations(field.FieldSymbol),
BoundObjectInitializerMember { MemberSymbol: PropertySymbol prop } => getSetterAnnotations(prop),
BoundObjectInitializerMember { MemberSymbol: FieldSymbol field } => getFieldAnnotations(field),
_ => FlowAnalysisAnnotations.None
};
......
......@@ -28032,6 +28032,132 @@ static void M(C c)
comp.VerifyDiagnostics();
}
[Fact, WorkItem(39966, "https://github.com/dotnet/roslyn/issues/39966")]
public void AllowNull_Property_InObjectInitializer()
{
var source = @"
using System.Diagnostics.CodeAnalysis;
public class C
{
[AllowNull] public C P { get; set; } // 1
}
class Program
{
static void M(C c1)
{
c1.P = null;
new C
{
P = null
};
}
}";
var comp = CreateNullableCompilation(new[] { source, AllowNullAttributeDefinition });
comp.VerifyDiagnostics(
// (5,26): warning CS8618: Non-nullable property 'P' is uninitialized. Consider declaring the property as nullable.
// [AllowNull] public C P { get; set; } // 1
Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "P").WithArguments("property", "P").WithLocation(5, 26));
}
[Fact, WorkItem(39966, "https://github.com/dotnet/roslyn/issues/39966")]
public void AllowNull_Field_InObjectInitializer()
{
var source = @"
using System.Diagnostics.CodeAnalysis;
public class C
{
[AllowNull] public C F; // 1
}
class Program
{
static void M(C c1)
{
c1.F = null;
new C
{
F = null
};
}
}";
var comp = CreateNullableCompilation(new[] { source, AllowNullAttributeDefinition });
comp.VerifyDiagnostics(
// (5,26): warning CS8618: Non-nullable field 'F' is uninitialized. Consider declaring the field as nullable.
// [AllowNull] public C F; // 1
Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "F").WithArguments("field", "F").WithLocation(5, 26));
}
[Fact, WorkItem(39966, "https://github.com/dotnet/roslyn/issues/39966")]
public void DisallowNull_Property_InObjectInitializer()
{
var source = @"
using System.Diagnostics.CodeAnalysis;
public class C
{
[DisallowNull] public C? P { get; set; }
}
class Program
{
static void M(C c1)
{
c1.P = null; // 1
new C
{
P = null // 2
};
}
}";
var comp = CreateNullableCompilation(new[] { source, DisallowNullAttributeDefinition });
comp.VerifyDiagnostics(
// (12,16): warning CS8625: Cannot convert null literal to non-nullable reference type.
// c1.P = null; // 1
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(12, 16),
// (16,17): warning CS8625: Cannot convert null literal to non-nullable reference type.
// P = null // 2
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(16, 17));
}
[Fact, WorkItem(39966, "https://github.com/dotnet/roslyn/issues/39966")]
public void DisallowNull_Field_InObjectInitializer()
{
var source = @"
using System.Diagnostics.CodeAnalysis;
public class C
{
[DisallowNull] public C? F;
}
class Program
{
static void M(C c1)
{
c1.F = null; // 1
new C
{
F = null // 2
};
}
}";
var comp = CreateNullableCompilation(new[] { source, DisallowNullAttributeDefinition });
comp.VerifyDiagnostics(
// (12,16): warning CS8625: Cannot convert null literal to non-nullable reference type.
// c1.F = null; // 1
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(12, 16),
// (16,17): warning CS8625: Cannot convert null literal to non-nullable reference type.
// F = null // 2
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(16, 17));
}
[Fact]
public void AllowNull_Property_InDeconstructionAssignment()
{
......@@ -10904,5 +10904,24 @@ static void Main()
Diagnostic(ErrorCode.ERR_ConstantStringTooLong, "C1").WithLocation(28, 68)
);
}
[Fact, WorkItem(39975, "https://github.com/dotnet/roslyn/issues/39975")]
public void EnsureOperandsConvertedInErrorExpression_01()
{
string source =
@"class C
{
static unsafe void M(dynamic d, int* p)
{
d += p;
}
}
";
CreateCompilation(source, options: TestOptions.ReleaseDll.WithAllowUnsafe(true)).VerifyDiagnostics(
// (5,9): error CS0019: Operator '+=' cannot be applied to operands of type 'dynamic' and 'int*'
// d += p;
Diagnostic(ErrorCode.ERR_BadBinaryOps, "d += p").WithArguments("+=", "dynamic", "int*").WithLocation(5, 9)
);
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册