diff --git a/src/Cli/dotnet/Commands/Run/CSharpCompilerCommand.cs b/src/Cli/dotnet/Commands/Run/CSharpCompilerCommand.cs
index 84ac2b073fe0..d40970596c95 100644
--- a/src/Cli/dotnet/Commands/Run/CSharpCompilerCommand.cs
+++ b/src/Cli/dotnet/Commands/Run/CSharpCompilerCommand.cs
@@ -106,8 +106,9 @@ public int Execute(out bool fallbackToNormalBuild)
// Process the response.
var exitCode = ProcessBuildResponse(responseTask.Result, out fallbackToNormalBuild);
- // Copy from obj to bin.
- if (BuildResultFile != null &&
+ // Copy from obj to bin only if the build succeeded.
+ if (exitCode == 0 &&
+ BuildResultFile != null &&
CSharpCommandLineParser.Default.Parse(CscArguments, BaseDirectory, sdkDirectory: null) is { OutputFileName: { } outputFileName } parsedArgs)
{
var objFile = new FileInfo(parsedArgs.GetOutputFilePath(outputFileName));
diff --git a/test/dotnet.Tests/CommandTests/Run/RunFileTests.cs b/test/dotnet.Tests/CommandTests/Run/RunFileTests.cs
index 5d7b53c65a3e..8c48225d55c9 100644
--- a/test/dotnet.Tests/CommandTests/Run/RunFileTests.cs
+++ b/test/dotnet.Tests/CommandTests/Run/RunFileTests.cs
@@ -3576,6 +3576,57 @@ public void CscOnly_AfterMSBuild_SpacesInPath()
Build(testInstance, BuildLevel.Csc, expectedOutput: "v2 Release", programFileName: programFileName);
}
+ ///
+ /// Testing optimization .
+ /// When compilation fails, the obj dll should not be copied to bin directory.
+ /// This prevents spurious errors if the dll file was not even produced by roslyn due to compilation errors.
+ ///
+ [Fact]
+ public void CscOnly_AfterMSBuild_CompilationFailure_NoCopyToBin()
+ {
+ var testInstance = _testAssetsManager.CreateTestDirectory(baseDirectory: OutOfTreeBaseDirectory);
+
+ // First, create a valid program and build it successfully
+ var programPath = Path.Join(testInstance.Path, "Program.cs");
+ var code = """
+ #:property PublishAot=false
+ Console.WriteLine("version 1");
+ """;
+ File.WriteAllText(programPath, code);
+
+ var artifactsDir = VirtualProjectBuildingCommand.GetArtifactsPath(programPath);
+ if (Directory.Exists(artifactsDir)) Directory.Delete(artifactsDir, recursive: true);
+
+ Build(testInstance, BuildLevel.All, expectedOutput: "version 1");
+
+ // Verify that the dlls were created
+ var objDll = Path.Join(artifactsDir, "obj", "debug", "Program.dll");
+ new FileInfo(objDll).Should().Exist();
+ var binDll = Path.Join(artifactsDir, "bin", "debug", "Program.dll");
+ new FileInfo(binDll).Should().Exist();
+
+ // Delete the dlls
+ File.Delete(objDll);
+ File.Delete(binDll);
+
+ // Write invalid code that causes compilation to fail
+ code = code.Replace(";", "");
+ File.WriteAllText(programPath, code);
+
+ // Try to build the invalid code
+ new DotnetCommand(Log, "run", "-bl", "Program.cs")
+ .WithWorkingDirectory(testInstance.Path)
+ .Execute()
+ .Should().Fail()
+ .And.HaveStdOutContaining(CliCommandStrings.NoBinaryLogBecauseRunningJustCsc)
+ // error CS1002: ; expected
+ .And.HaveStdOutContaining("error CS1002")
+ .And.HaveStdErrContaining(CliCommandStrings.RunCommandException);
+
+ new FileInfo(objDll).Should().NotExist();
+ new FileInfo(binDll).Should().NotExist();
+ }
+
///
/// See .
///