mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-01-25 10:48:14 +00:00
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:
parent
990a692f4a
commit
1121de36c2
@ -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">;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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; };
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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()));
|
||||
|
Loading…
x
Reference in New Issue
Block a user