r199513 - Fix string-literal to char* conversion in overload resolution for C++11

Ismail Pazarbasi ismail.pazarbasi at gmail.com
Fri Jan 17 13:08:52 PST 2014


Author: ismailp
Date: Fri Jan 17 15:08:52 2014
New Revision: 199513

URL: http://llvm.org/viewvc/llvm-project?rev=199513&view=rev
Log:
Fix string-literal to char* conversion in overload resolution for C++11

String literal to char* conversion is deprecated in C++03, and is removed in
C++11. We still accept this conversion in C++11 mode as an extension, if we find
it in the best viable function.


Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/Sema/SemaExprCXX.cpp
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/test/SemaCXX/cxx0x-type-convert-construct.cpp
    cfe/trunk/test/SemaCXX/deprecated.cpp
    cfe/trunk/test/SemaCXX/overload-0x.cpp
    cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=199513&r1=199512&r2=199513&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Fri Jan 17 15:08:52 2014
@@ -4534,6 +4534,9 @@ def ext_array_init_parens : ExtWarn<
 def warn_deprecated_string_literal_conversion : Warning<
   "conversion from string literal to %0 is deprecated">,
   InGroup<CXX11CompatDeprecatedWritableStr>;
+def ext_deprecated_string_literal_conversion : ExtWarn<
+  "ISO C++11 does not allow conversion from string literal to %0">,
+  InGroup<CXX11CompatDeprecatedWritableStr>, SFINAEFailure;
 def warn_deprecated_string_literal_conversion_c : Warning<
   "dummy warning to enable -fconst-strings">, InGroup<DeprecatedWritableStr>, DefaultIgnore;
 def err_realimag_invalid_type : Error<"invalid type %0 to %1 operator">;

Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=199513&r1=199512&r2=199513&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Fri Jan 17 15:08:52 2014
@@ -3058,9 +3058,12 @@ Sema::PerformImplicitConversion(Expr *Fr
                              CK_NoOp, VK, /*BasePath=*/0, CCK).take();
 
     if (SCS.DeprecatedStringLiteralToCharPtr &&
-        !getLangOpts().WritableStrings)
-      Diag(From->getLocStart(), diag::warn_deprecated_string_literal_conversion)
+        !getLangOpts().WritableStrings) {
+      Diag(From->getLocStart(), getLangOpts().CPlusPlus11
+           ? diag::ext_deprecated_string_literal_conversion
+           : diag::warn_deprecated_string_literal_conversion)
         << ToType.getNonReferenceType();
+    }
 
     break;
   }

Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=199513&r1=199512&r2=199513&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Fri Jan 17 15:08:52 2014
@@ -1443,7 +1443,6 @@ static bool IsStandardConversion(Sema &S
 
   // Standard conversions (C++ [conv])
   SCS.setAsIdentityConversion();
-  SCS.DeprecatedStringLiteralToCharPtr = false;
   SCS.IncompatibleObjC = false;
   SCS.setFromType(FromType);
   SCS.CopyConstructor = 0;
@@ -1542,7 +1541,7 @@ static bool IsStandardConversion(Sema &S
     FromType = S.Context.getArrayDecayedType(FromType);
 
     if (S.IsStringLiteralToNonConstPointerConversion(From, ToType)) {
-      // This conversion is deprecated. (C++ D.4).
+      // This conversion is deprecated in C++03 (D.4)
       SCS.DeprecatedStringLiteralToCharPtr = true;
 
       // For the purpose of ranking in overload resolution
@@ -3259,18 +3258,15 @@ Sema::DiagnoseMultipleUserDefinedConvers
     IsUserDefinedConversion(*this, From, ToType, ICS.UserDefined,
                             CandidateSet, false, false);
   if (OvResult == OR_Ambiguous)
-    Diag(From->getLocStart(),
-         diag::err_typecheck_ambiguous_condition)
-          << From->getType() << ToType << From->getSourceRange();
+    Diag(From->getLocStart(), diag::err_typecheck_ambiguous_condition)
+        << From->getType() << ToType << From->getSourceRange();
   else if (OvResult == OR_No_Viable_Function && !CandidateSet.empty()) {
     if (!RequireCompleteType(From->getLocStart(), ToType,
-                          diag::err_typecheck_nonviable_condition_incomplete,
+                             diag::err_typecheck_nonviable_condition_incomplete,
                              From->getType(), From->getSourceRange()))
-      Diag(From->getLocStart(),
-           diag::err_typecheck_nonviable_condition)
-           << From->getType() << From->getSourceRange() << ToType;
-  }
-  else
+      Diag(From->getLocStart(), diag::err_typecheck_nonviable_condition)
+          << From->getType() << From->getSourceRange() << ToType;
+  } else
     return false;
   CandidateSet.NoteCandidates(*this, OCD_AllCandidates, From);
   return true;
@@ -3280,37 +3276,43 @@ Sema::DiagnoseMultipleUserDefinedConvers
 /// of two user-defined conversion sequences to determine whether any ordering
 /// is possible.
 static ImplicitConversionSequence::CompareKind
-compareConversionFunctions(Sema &S,
-                           FunctionDecl *Function1,
+compareConversionFunctions(Sema &S, FunctionDecl *Function1,
                            FunctionDecl *Function2) {
   if (!S.getLangOpts().ObjC1 || !S.getLangOpts().CPlusPlus11)
     return ImplicitConversionSequence::Indistinguishable;
-  
+
   // Objective-C++:
   //   If both conversion functions are implicitly-declared conversions from
-  //   a lambda closure type to a function pointer and a block pointer, 
+  //   a lambda closure type to a function pointer and a block pointer,
   //   respectively, always prefer the conversion to a function pointer,
   //   because the function pointer is more lightweight and is more likely
   //   to keep code working.
   CXXConversionDecl *Conv1 = dyn_cast<CXXConversionDecl>(Function1);
   if (!Conv1)
     return ImplicitConversionSequence::Indistinguishable;
-    
+
   CXXConversionDecl *Conv2 = dyn_cast<CXXConversionDecl>(Function2);
   if (!Conv2)
     return ImplicitConversionSequence::Indistinguishable;
-  
+
   if (Conv1->getParent()->isLambda() && Conv2->getParent()->isLambda()) {
     bool Block1 = Conv1->getConversionType()->isBlockPointerType();
     bool Block2 = Conv2->getConversionType()->isBlockPointerType();
     if (Block1 != Block2)
-      return Block1? ImplicitConversionSequence::Worse 
-                   : ImplicitConversionSequence::Better;
+      return Block1 ? ImplicitConversionSequence::Worse
+                    : ImplicitConversionSequence::Better;
   }
 
   return ImplicitConversionSequence::Indistinguishable;
 }
-  
+
+static bool hasDeprecatedStringLiteralToCharPtrConversion(
+    const ImplicitConversionSequence &ICS) {
+  return (ICS.isStandard() && ICS.Standard.DeprecatedStringLiteralToCharPtr) ||
+         (ICS.isUserDefined() &&
+          ICS.UserDefined.Before.DeprecatedStringLiteralToCharPtr);
+}
+
 /// CompareImplicitConversionSequences - Compare two implicit
 /// conversion sequences to determine whether one is better than the
 /// other or if they are indistinguishable (C++ 13.3.3.2).
@@ -3333,6 +3335,32 @@ CompareImplicitConversionSequences(Sema
   //   described in 13.3.3.2, the ambiguous conversion sequence is
   //   treated as a user-defined sequence that is indistinguishable
   //   from any other user-defined conversion sequence.
+
+  // String literal to 'char *' conversion has been deprecated in C++03. It has
+  // been removed from C++11. We still accept this conversion, if it happens at
+  // the best viable function. Otherwise, this conversion is considered worse
+  // than ellipsis conversion. Consider this as an extension; this is not in the
+  // standard. For example:
+  //
+  // int &f(...);    // #1
+  // void f(char*);  // #2
+  // void g() { int &r = f("foo"); }
+  //
+  // In C++03, we pick #2 as the best viable function.
+  // In C++11, we pick #1 as the best viable function, because ellipsis
+  // conversion is better than string-literal to char* conversion (since there
+  // is no such conversion in C++11). If there was no #1 at all or #1 couldn't
+  // convert arguments, #2 would be the best viable function in C++11.
+  // If the best viable function has this conversion, a warning will be issued
+  // in C++03, or an ExtWarn (+SFINAE failure) will be issued in C++11.
+
+  if (S.getLangOpts().CPlusPlus11 && !S.getLangOpts().WritableStrings &&
+      hasDeprecatedStringLiteralToCharPtrConversion(ICS1) !=
+      hasDeprecatedStringLiteralToCharPtrConversion(ICS2))
+    return hasDeprecatedStringLiteralToCharPtrConversion(ICS1)
+               ? ImplicitConversionSequence::Worse
+               : ImplicitConversionSequence::Better;
+
   if (ICS1.getKindRank() < ICS2.getKindRank())
     return ImplicitConversionSequence::Better;
   if (ICS2.getKindRank() < ICS1.getKindRank())
@@ -4244,6 +4272,7 @@ TryReferenceInit(Sema &S, Expr *Init, Qu
       ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false;
       ICS.Standard.ObjCLifetimeConversionBinding = ObjCLifetimeConversion;
       ICS.Standard.CopyConstructor = 0;
+      ICS.Standard.DeprecatedStringLiteralToCharPtr = false;
 
       // Nothing more to do: the inaccessibility/ambiguity check for
       // derived-to-base conversions is suppressed when we're
@@ -4318,6 +4347,7 @@ TryReferenceInit(Sema &S, Expr *Init, Qu
     ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false;
     ICS.Standard.ObjCLifetimeConversionBinding = ObjCLifetimeConversion;
     ICS.Standard.CopyConstructor = 0;
+    ICS.Standard.DeprecatedStringLiteralToCharPtr = false;
     return ICS;
   }
 

Modified: cfe/trunk/test/SemaCXX/cxx0x-type-convert-construct.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx0x-type-convert-construct.cpp?rev=199513&r1=199512&r2=199513&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx0x-type-convert-construct.cpp (original)
+++ cfe/trunk/test/SemaCXX/cxx0x-type-convert-construct.cpp Fri Jan 17 15:08:52 2014
@@ -9,9 +9,9 @@ void f() {
   Ustr = U"a UTF-32 string"; // expected-error {{assigning to 'char32_t *' from incompatible type 'const char32_t [16]'}}
 
   char *Rstr;
-  Rstr = R"foo(a raw string)foo"; // expected-warning{{conversion from string literal to 'char *' is deprecated}}
+  Rstr = R"foo(a raw string)foo"; // expected-warning{{ISO C++11 does not allow conversion from string literal to 'char *'}}
   wchar_t *LRstr;
-  LRstr = LR"foo(a wide raw string)foo"; // expected-warning{{conversion from string literal to 'wchar_t *' is deprecated}}
+  LRstr = LR"foo(a wide raw string)foo"; // expected-warning{{ISO C++11 does not allow conversion from string literal to 'wchar_t *'}}
   char *u8Rstr;
   u8Rstr = u8R"foo(a UTF-8 raw string)foo"; // expected-error {{assigning to 'char *' from incompatible type 'const char [19]'}}
   char16_t *uRstr;

Modified: cfe/trunk/test/SemaCXX/deprecated.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/deprecated.cpp?rev=199513&r1=199512&r2=199513&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/deprecated.cpp (original)
+++ cfe/trunk/test/SemaCXX/deprecated.cpp Fri Jan 17 15:08:52 2014
@@ -24,12 +24,15 @@ void stuff() {
   register int m asm("rbx"); // no-warning
 
   int k = to_int(n); // no-warning
-
   bool b;
   ++b; // expected-warning {{incrementing expression of type bool is deprecated}}
 
-  // FIXME: This is ill-formed in C++11.
-  char *p = "foo"; // expected-warning {{conversion from string literal to 'char *' is deprecated}}
+  char *p = "foo";
+#if __cplusplus < 201103L
+  // expected-warning at -2 {{conversion from string literal to 'char *' is deprecated}}
+#else
+  // expected-warning at -4 {{ISO C++11 does not allow conversion from string literal to 'char *'}}
+#endif
 }
 
 struct S { int n; };

Modified: cfe/trunk/test/SemaCXX/overload-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/overload-0x.cpp?rev=199513&r1=199512&r2=199513&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/overload-0x.cpp (original)
+++ cfe/trunk/test/SemaCXX/overload-0x.cpp Fri Jan 17 15:08:52 2014
@@ -1,7 +1,11 @@
-// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s 
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s
 
 namespace test0 {
-  struct A { // expected-note {{candidate function (the implicit copy assignment operator) not viable: 'this' argument has type 'const test0::A', but method is not marked const}} expected-note {{candidate function (the implicit move assignment operator) not viable: 'this' argument has type 'const test0::A', but method is not marked const}}
+  struct A { // expected-note {{candidate function (the implicit copy assignment operator) not viable: 'this' argument has type 'const test0::A', but method is not marked const}}
+#if __cplusplus >= 201103L
+  // expected-note at -2 {{candidate function (the implicit move assignment operator) not viable: 'this' argument has type 'const test0::A', but method is not marked const}}
+#endif
     A &operator=(void*); // expected-note {{candidate function not viable: 'this' argument has type 'const test0::A', but method is not marked const}}
   };
 
@@ -9,3 +13,79 @@ namespace test0 {
     a = "help"; // expected-error {{no viable overloaded '='}}
   }
 }
+
+namespace PR16314 {
+  void f(char*);
+  int &f(...);
+  void x()
+  {
+    int &n = f("foo");
+#if __cplusplus < 201103L
+    // expected-warning at -2 {{conversion from string literal to 'char *' is deprecated}}
+    // expected-error at -3 {{non-const lvalue reference to type 'int' cannot bind to a temporary of type 'void'}}
+#endif
+  }
+}
+
+namespace warn_if_best {
+  int f(char *);
+  void f(double);
+  void x()
+  {
+    int n = f("foo");
+#if __cplusplus < 201103L
+    // expected-warning at -2 {{conversion from string literal to 'char *' is deprecated}}
+#else
+    // expected-warning at -4 {{ISO C++11 does not allow conversion from string literal to 'char *'}}
+#endif
+  }
+}
+
+namespace userdefined_vs_illformed {
+  struct X { X(const char *); };
+
+  void *f(char *p); // best for C++03
+  double f(X x);  // best for C++11
+  void g()
+  {
+    double d = f("foo");
+#if __cplusplus < 201103L
+    // expected-warning at -2 {{conversion from string literal to 'char *' is deprecated}}
+    // expected-error at -3 {{cannot initialize a variable of type 'double' with an rvalue of type 'void *'}}
+#endif
+  }
+}
+
+namespace sfinae_test {
+  int f(int, char*);
+
+  template<int T>
+  struct S { typedef int type; };
+
+  template<>
+  struct S<sizeof(int)> { typedef void type; };
+
+  // C++11: SFINAE failure
+  // C++03: ok
+  template<typename T> int cxx11_ignored(T, typename S<sizeof(f(T(), "foo"))>::type *);
+#if __cplusplus < 201103L
+  // expected-warning at -2 {{conversion from string literal to 'char *' is deprecated}}
+#else
+  // expected-note at -4 {{candidate template ignored: substitution failure}}
+#endif
+
+  // C++11: better than latter
+  // C++03: worse than latter
+  template<typename T> void g(T, ...);
+  template<typename T> int g(T, typename S<sizeof(f(T(), "foo"))>::type *);
+#if __cplusplus < 201103L
+  // expected-warning at -2 {{conversion from string literal to 'char *' is deprecated}}
+#endif
+
+  int a = cxx11_ignored(0, 0);
+  int b = g(0, 0);
+#if __cplusplus >= 201103L
+  // expected-error at -3 {{no matching function for call to 'cxx11_ignored'}}
+  // expected-error at -3 {{cannot initialize a variable of type 'int' with an rvalue of type 'void'}}
+#endif
+}

Modified: cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp?rev=199513&r1=199512&r2=199513&view=diff
==============================================================================
--- cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp (original)
+++ cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp Fri Jan 17 15:08:52 2014
@@ -2608,13 +2608,13 @@ TEST(ReinterpretCast, DoesNotMatchOtherC
 }
 
 TEST(FunctionalCast, MatchesSimpleCase) {
-  std::string foo_class = "class Foo { public: Foo(char*); };";
+  std::string foo_class = "class Foo { public: Foo(const char*); };";
   EXPECT_TRUE(matches(foo_class + "void r() { Foo f = Foo(\"hello world\"); }",
                       functionalCastExpr()));
 }
 
 TEST(FunctionalCast, DoesNotMatchOtherCasts) {
-  std::string FooClass = "class Foo { public: Foo(char*); };";
+  std::string FooClass = "class Foo { public: Foo(const char*); };";
   EXPECT_TRUE(
       notMatches(FooClass + "void r() { Foo f = (Foo) \"hello world\"; }",
                  functionalCastExpr()));





More information about the cfe-commits mailing list