Windows fixes.

This CL fixes up some issues which give compile errors when building
with Visual Studio.

Change-Id: Ib76644d869dd2adccd579621d18804d84b65a74c
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/20940
Reviewed-by: David Neto <dneto@google.com>
diff --git a/.gitignore b/.gitignore
index 139e452..b21a226 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,7 @@
 .DS_Store
 .gclient
 .gclient_entries
+.vs
 .vscode
 build
 buildtools
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 29bf7ea..b99473a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -39,6 +39,14 @@
 
 option(TINT_CHECK_CHROMIUM_STYLE "Check for [chromium-style] issues during build" OFF)
 
+if(WIN32)
+  # On Windows, CMake by default compiles with the shared CRT.
+  # Default it to the static CRT.
+  option(TINT_ENABLE_SHARED_CRT
+         "Tint: Use the shared CRT with MSVC instead of the static CRT"
+         ${TINT_ENABLE_SHARED_CRT})
+endif(WIN32)
+
 message(STATUS "Tint build docs: ${TINT_BUILD_DOCS}")
 message(STATUS "Tint build SPIR-V reader: ${TINT_BUILD_SPV_READER}")
 message(STATUS "Tint build WGSL reader: ${TINT_BUILD_WGSL_READER}")
@@ -81,6 +89,25 @@
   message("Doxygen not found. Skipping documentation")
 endif()
 
+if(MSVC)
+  # We don't want to have to copy the C Runtime DLL everywhere the executable
+  # goes.  So by default compile code to assume the CRT is statically linked,
+  # i.e. use /MT* options.  For debug builds use /MTd, and for release builds
+  # use /MT.  If TINT_ENABLE_SHARED_CRT is ON, then use the shared C runtime.
+  # Modify the project-wide options variables. This is ugly, but seems to be
+  # the state of the art.
+  if(NOT ${TINT_ENABLE_SHARED_CRT})
+    message(STATUS "Tint: Static C runtime selected: replacing /MD* with /MT*")
+    foreach (flag_var
+       CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE
+       CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO
+       CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
+       CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
+      string(REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
+    endforeach()
+  endif()
+endif()
+
 function(tint_default_compile_options TARGET)
   include_directories("${PROJECT_SOURCE_DIR}")
 
@@ -141,6 +168,8 @@
       /W3
       /WX
       /wd4068
+      /wd4244
+      /wd4267
       /wd4514
       /wd4571
       /wd4625
@@ -152,6 +181,19 @@
       /wd5027
     )
   endif()
+
+  if (NOT ${TINT_ENABLE_SHARED_CRT})
+    # For MinGW cross compile, statically link to the C++ runtime.
+    # But it still depends on MSVCRT.dll.
+    if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
+      if (${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU")
+        set_target_properties(${TARGET} PROPERTIES LINK_FLAGS
+          -static
+          -static-libgcc
+          -static-libstdc++)
+      endif()
+    endif()
+  endif()
 endfunction()
 
 add_subdirectory(third_party)
diff --git a/src/reader/wgsl/lexer_test.cc b/src/reader/wgsl/lexer_test.cc
index 3d7027f..71a1109 100644
--- a/src/reader/wgsl/lexer_test.cc
+++ b/src/reader/wgsl/lexer_test.cc
@@ -321,7 +321,7 @@
                     SignedIntData{"2", 2},
                     SignedIntData{"123", 123},
                     SignedIntData{"2147483647", 2147483647},
-                    SignedIntData{"-2147483648", -2147483648}));
+                    SignedIntData{"-2147483648", -2147483648LL}));
 
 using IntegerTest_Invalid = testing::TestWithParam<const char*>;
 TEST_P(IntegerTest_Invalid, Parses) {
diff --git a/src/reader/wgsl/parser_impl_const_literal_test.cc b/src/reader/wgsl/parser_impl_const_literal_test.cc
index fec1ad9..74bc6e2 100644
--- a/src/reader/wgsl/parser_impl_const_literal_test.cc
+++ b/src/reader/wgsl/parser_impl_const_literal_test.cc
@@ -49,7 +49,7 @@
   ASSERT_FALSE(p->has_error());
   ASSERT_NE(c, nullptr);
   ASSERT_TRUE(c->IsFloat());
-  EXPECT_FLOAT_EQ(c->AsFloat()->value(), 234e12);
+  EXPECT_FLOAT_EQ(c->AsFloat()->value(), 234e12f);
 }
 
 TEST_F(ParserImplTest, ConstLiteral_InvalidFloat) {
diff --git a/src/writer/spirv/builder.h b/src/writer/spirv/builder.h
index 87f8b24..823dcd9 100644
--- a/src/writer/spirv/builder.h
+++ b/src/writer/spirv/builder.h
@@ -45,10 +45,10 @@
     /// which we will use to evaluate the current set of accessors. This maybe
     /// the original variable, or maybe an intermediary if we had to evaulate
     /// the access chain early (in the case of a swizzle of an access chain).
-    uint32_t source_id;
+    uint32_t source_id = 0;
     /// The type of the current chain source. This type matches the deduced
     /// result_type of the current source defined above.
-    ast::type::Type* source_type;
+    ast::type::Type* source_type = nullptr;
     /// A list of access chain indices to emit. Note, we _only_ have access
     /// chain indices if the source is pointer.
     std::vector<uint32_t> access_chain_indices;
diff --git a/src/writer/spirv/instruction_test.cc b/src/writer/spirv/instruction_test.cc
index 65e0630..b512470 100644
--- a/src/writer/spirv/instruction_test.cc
+++ b/src/writer/spirv/instruction_test.cc
@@ -32,7 +32,7 @@
 
   const auto& ops = i.operands();
   EXPECT_TRUE(ops[0].IsFloat());
-  EXPECT_FLOAT_EQ(ops[0].to_f(), 1.2);
+  EXPECT_FLOAT_EQ(ops[0].to_f(), 1.2f);
 
   EXPECT_TRUE(ops[1].IsInt());
   EXPECT_EQ(ops[1].to_i(), 1u);
diff --git a/src/writer/spirv/operand.h b/src/writer/spirv/operand.h
index 844044d..79ad2eb 100644
--- a/src/writer/spirv/operand.h
+++ b/src/writer/spirv/operand.h
@@ -27,7 +27,7 @@
   /// The kind of the operand
   // Note, the `kInt` will cover most cases as things like IDs in SPIR-V are
   // just ints for the purpose of converting to binary.
-  enum Kind { kInt = 0, kFloat, kString };
+  enum class Kind { kInt = 0, kFloat, kString };
 
   /// Creates a float operand
   /// @param val the float value
diff --git a/src/writer/spirv/operand_test.cc b/src/writer/spirv/operand_test.cc
index 0bb1c26..405028e 100644
--- a/src/writer/spirv/operand_test.cc
+++ b/src/writer/spirv/operand_test.cc
@@ -26,7 +26,7 @@
 TEST_F(OperandTest, CreateFloat) {
   auto o = Operand::Float(1.2f);
   EXPECT_TRUE(o.IsFloat());
-  EXPECT_FLOAT_EQ(o.to_f(), 1.2);
+  EXPECT_FLOAT_EQ(o.to_f(), 1.2f);
 }
 
 TEST_F(OperandTest, CreateInt) {