There were some frustrating problems with the implementation of
-Wwrite-strings. First and foremost, once the positive form of the flag
was passed, it could never be disabled by passing -Wno-write-strings.
Also, the diagnostic engine couldn't in turn use -Wwrite-strings to
control diagnostics (as GCC does) because it was essentially hijacked to
drive the language semantics.

Fix this by giving CC1 a clean '-fconst-strings' flag to enable
const-qualified strings in C and ObjC compilations. Corresponding
'-fno-const-strings' is also added. Then the driver is taught to
introduce '-fconst-strings' in the CC1 command when '-Wwrite-strings'
dominates.

This entire flag is basically GCC-bug-compatibility driven, so we also
match GCC's bug where '-w' doesn't actually disable -Wwrite-strings. I'm
open to changing this though as it seems insane.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@130051 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td
index cef9496..442488b 100644
--- a/include/clang/Driver/CC1Options.td
+++ b/include/clang/Driver/CC1Options.td
@@ -257,8 +257,6 @@
   HelpText<"Use colors in diagnostics">;
 def Wno_rewrite_macros : Flag<"-Wno-rewrite-macros">,
   HelpText<"Silence ObjC rewriting warnings">;
-def Wwrite_strings : Flag<"-Wwrite-strings">,
-  HelpText<"Remove const qualifier from string literals">;
 def verify : Flag<"-verify">,
   HelpText<"Verify emitted diagnostics and warnings">;
 
@@ -526,6 +524,10 @@
   HelpText<"Process trigraph sequences">;
 def fwritable_strings : Flag<"-fwritable-strings">,
   HelpText<"Store string literals as writable data">;
+def fconst_strings : Flag<"-fconst-strings">,
+  HelpText<"Use a const qualified type for string literals in C and ObjC">;
+def fno_const_strings : Flag<"-fno-const-strings">,
+  HelpText<"Don't use a const qualified type for string literals in C and ObjC">;
 def fno_bitfield_type_align : Flag<"-fno-bitfield-type-align">,
   HelpText<"Ignore bit-field types when aligning structures">;
 def traditional_cpp : Flag<"-traditional-cpp">,
diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
index 6374eeb..06b3d34 100644
--- a/include/clang/Driver/Options.td
+++ b/include/clang/Driver/Options.td
@@ -175,6 +175,8 @@
 def Wp_COMMA : CommaJoined<"-Wp,">,
   HelpText<"Pass the comma separated arguments in <arg> to the preprocessor">,
   MetaVarName<"<arg>">;
+def Wwrite_strings : Flag<"-Wwrite-strings">, Group<W_Group>;
+def Wno_write_strings : Flag<"-Wno-write-strings">, Group<W_Group>;
 def W_Joined : Joined<"-W">, Group<W_Group>;
 def Xanalyzer : Separate<"-Xanalyzer">,
   HelpText<"Pass <arg> to the static analyzer">, MetaVarName<"<arg>">;
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index 4e94346..436a2a4 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -1353,6 +1353,15 @@
     Args.AddLastArg(CmdArgs, options::OPT_trigraphs);
   }
 
+  // Map the bizarre '-Wwrite-strings' flag to a more sensible
+  // '-fconst-strings'; this better indicates its actual behavior.
+  if (Args.hasFlag(options::OPT_Wwrite_strings, options::OPT_Wno_write_strings,
+                   false)) {
+    // For perfect compatibility with GCC, we do this even in the presence of
+    // '-w'. This flag names something other than a warning for GCC.
+    CmdArgs.push_back("-fconst-strings");
+  }
+
   // Translate GCC's misnamer '-fasm' arguments to '-fgnu-keywords'.
   if (Arg *Asm = Args.getLastArg(options::OPT_fasm, options::OPT_fno_asm)) {
     if (Asm->getOption().matches(options::OPT_fasm))
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 3f3c1d8..0dd2093 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -577,7 +577,7 @@
   if (Opts.WritableStrings)
     Res.push_back("-fwritable-strings");
   if (Opts.ConstStrings)
-    Res.push_back("-Wwrite-strings");
+    Res.push_back("-fconst-strings");
   if (!Opts.LaxVectorConversions)
     Res.push_back("-fno-lax-vector-conversions");
   if (Opts.AltiVec)
@@ -1475,7 +1475,8 @@
   Opts.MSCVersion = Args.getLastArgIntValue(OPT_fmsc_version, 0, Diags);
   Opts.Borland = Args.hasArg(OPT_fborland_extensions);
   Opts.WritableStrings = Args.hasArg(OPT_fwritable_strings);
-  Opts.ConstStrings = Args.hasArg(OPT_Wwrite_strings);
+  Opts.ConstStrings = Args.hasFlag(OPT_fconst_strings, OPT_fno_const_strings,
+                                   Opts.ConstStrings);
   if (Args.hasArg(OPT_fno_lax_vector_conversions))
     Opts.LaxVectorConversions = 0;
   if (Args.hasArg(OPT_fno_threadsafe_statics))
diff --git a/test/Driver/clang_f_opts.c b/test/Driver/clang_f_opts.c
index 8e6b0fe..8d63ca8 100644
--- a/test/Driver/clang_f_opts.c
+++ b/test/Driver/clang_f_opts.c
@@ -12,3 +12,10 @@
 // CHECK-OPTIONS2: -fshort-wchar
 // CHECK-OPTIONS2: -fno-common
 // CHECK-OPTIONS2: -fno-show-source-location
+
+// RUN: %clang -### -S -Wwrite-strings %s 2>&1 | FileCheck -check-prefix=WRITE-STRINGS1 %s
+// WRITE-STRINGS1: -fconst-strings
+// RUN: %clang -### -S -Wwrite-strings -Wno-write-strings %s 2>&1 | FileCheck -check-prefix=WRITE-STRINGS2 %s
+// WRITE-STRINGS2-NOT: -fconst-strings
+// RUN: %clang -### -S -Wwrite-strings -w %s 2>&1 | FileCheck -check-prefix=WRITE-STRINGS3 %s
+// WRITE-STRINGS3: -fconst-strings
diff --git a/test/Sema/warn-write-strings.c b/test/Sema/warn-write-strings.c
index dd0bb8a..dee554c 100644
--- a/test/Sema/warn-write-strings.c
+++ b/test/Sema/warn-write-strings.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -verify -fsyntax-only -Wwrite-strings %s
+// RUN: %clang_cc1 -verify -fsyntax-only -fconst-strings %s
 
 // PR4804
 char* x = "foo"; // expected-warning {{initializing 'char *' with an expression of type 'const char [4]' discards qualifiers}}
diff --git a/test/SemaObjC/warn-write-strings.m b/test/SemaObjC/warn-write-strings.m
index 450d0a6..163c864 100644
--- a/test/SemaObjC/warn-write-strings.m
+++ b/test/SemaObjC/warn-write-strings.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -verify -fsyntax-only -Wwrite-strings %s
+// RUN: %clang_cc1 -verify -fsyntax-only -fconst-strings %s
 
 // PR4804
 char* x = "foo"; // expected-warning {{initializing 'char *' with an expression of type 'const char [4]' discards qualifiers}}