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.

llvm-svn: 199513
This commit is contained in:
Ismail Pazarbasi 2014-01-17 21:08:52 +00:00
parent 990a692f4a
commit 1121de36c2
7 changed files with 150 additions and 31 deletions

View File

@ -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">;

View File

@ -3058,9 +3058,12 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
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;
}

View File

@ -1443,7 +1443,6 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
// 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, Expr* From, QualType ToType,
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::DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType) {
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::DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType) {
/// 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 &S,
// 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, QualType DeclType,
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, QualType DeclType,
ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false;
ICS.Standard.ObjCLifetimeConversionBinding = ObjCLifetimeConversion;
ICS.Standard.CopyConstructor = 0;
ICS.Standard.DeprecatedStringLiteralToCharPtr = false;
return ICS;
}

View File

@ -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;

View File

@ -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@-2 {{conversion from string literal to 'char *' is deprecated}}
#else
// expected-warning@-4 {{ISO C++11 does not allow conversion from string literal to 'char *'}}
#endif
}
struct S { int n; };

View File

@ -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@-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@-2 {{conversion from string literal to 'char *' is deprecated}}
// expected-error@-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@-2 {{conversion from string literal to 'char *' is deprecated}}
#else
// expected-warning@-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@-2 {{conversion from string literal to 'char *' is deprecated}}
// expected-error@-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@-2 {{conversion from string literal to 'char *' is deprecated}}
#else
// expected-note@-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@-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@-3 {{no matching function for call to 'cxx11_ignored'}}
// expected-error@-3 {{cannot initialize a variable of type 'int' with an rvalue of type 'void'}}
#endif
}

View File

@ -2608,13 +2608,13 @@ TEST(ReinterpretCast, DoesNotMatchOtherCasts) {
}
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()));