Added new test for user defined conversion sequence.
User defined conversions were handled incorrectly in previous revision.
Added DeprecatedStringLiteralToCharPtr initializations, so that we don't have
to check standard conversion sequence has Array to
pointer->identity->qualification conversions (previously needed for checking
DeprecatedStringLiteralToCharPtr).
Added checks to ensure we pick the correct overloads.
Hi rsmith,
http://llvm-reviews.chandlerc.com/D1965
CHANGE SINCE LAST DIFF
http://llvm-reviews.chandlerc.com/D1965?vs=5351&id=5530#toc
Files:
include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaExprCXX.cpp
lib/Sema/SemaOverload.cpp
test/SemaCXX/cxx0x-type-convert-construct.cpp
test/SemaCXX/deprecated.cpp
test/SemaCXX/overload-0x.cpp
unittests/ASTMatchers/ASTMatchersTest.cpp
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -4490,6 +4490,10 @@
InGroup<DiagGroup<"gnu-array-member-paren-init">>, DefaultError;
def warn_deprecated_string_literal_conversion : Warning<
"conversion from string literal to %0 is deprecated">, InGroup<DeprecatedWritableStr>;
+def ext_deprecated_string_literal_conversion : ExtWarn<
+ "conversion from string literal to %0 is ill-formed in C++11">, InGroup<DeprecatedWritableStr>;
+def err_deprecated_string_literal_conversion : Error<
+ "conversion from string literal to %0 is ill-formed in C++11">;
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">;
Index: lib/Sema/SemaExprCXX.cpp
===================================================================
--- lib/Sema/SemaExprCXX.cpp
+++ lib/Sema/SemaExprCXX.cpp
@@ -3033,9 +3033,16 @@
CK_NoOp, VK, /*BasePath=*/0, CCK).take();
if (SCS.DeprecatedStringLiteralToCharPtr &&
- !getLangOpts().WritableStrings)
- Diag(From->getLocStart(), diag::warn_deprecated_string_literal_conversion)
- << ToType.getNonReferenceType();
+ !getLangOpts().WritableStrings) {
+ unsigned DiagID =
+ getLangOpts().CPlusPlus11
+ ? (isSFINAEContext()
+ ? diag::err_deprecated_string_literal_conversion
+ : diag::ext_deprecated_string_literal_conversion)
+ : diag::warn_deprecated_string_literal_conversion;
+
+ Diag(From->getLocStart(), DiagID) << ToType.getNonReferenceType();
+ }
break;
}
Index: lib/Sema/SemaOverload.cpp
===================================================================
--- lib/Sema/SemaOverload.cpp
+++ lib/Sema/SemaOverload.cpp
@@ -1149,6 +1149,7 @@
ICS.Standard.setFromType(From->getType());
ICS.Standard.setAllToTypes(ToType);
ICS.Standard.CopyConstructor = Constructor;
+ ICS.Standard.DeprecatedStringLiteralToCharPtr = false;
if (ToCanon != FromCanon)
ICS.Standard.Second = ICK_Derived_To_Base;
}
@@ -1241,6 +1242,7 @@
ICS.Standard.setAsIdentityConversion();
ICS.Standard.setFromType(FromType);
ICS.Standard.setAllToTypes(ToType);
+ ICS.Standard.DeprecatedStringLiteralToCharPtr = false;
// We don't actually check at this point whether there is a valid
// copy/move constructor, since overloading just assumes that it
@@ -1524,7 +1526,7 @@
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
@@ -2982,9 +2984,11 @@
User.HadMultipleCandidates = HadMultipleCandidates;
User.ConversionFunction = Constructor;
User.FoundConversionFunction = Best->FoundDecl;
+ User.Before.DeprecatedStringLiteralToCharPtr = false;
User.After.setAsIdentityConversion();
User.After.setFromType(ThisType->getAs<PointerType>()->getPointeeType());
User.After.setAllToTypes(ToType);
+ User.After.DeprecatedStringLiteralToCharPtr = false;
return OR_Success;
}
@@ -3176,6 +3180,7 @@
if (isa<InitListExpr>(From)) {
// Initializer lists don't have conversions as such.
User.Before.setAsIdentityConversion();
+ User.Before.DeprecatedStringLiteralToCharPtr = false;
} else {
if (Best->Conversions[0].isEllipsis())
User.EllipsisConversion = true;
@@ -3190,6 +3195,7 @@
User.After.setAsIdentityConversion();
User.After.setFromType(ThisType->getAs<PointerType>()->getPointeeType());
User.After.setAllToTypes(ToType);
+ User.After.DeprecatedStringLiteralToCharPtr = false;
return OR_Success;
}
if (CXXConversionDecl *Conversion
@@ -3241,18 +3247,15 @@
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;
@@ -3262,37 +3265,45 @@
/// 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) {
+ if (ICS.isStandard())
+ return ICS.Standard.DeprecatedStringLiteralToCharPtr;
+ if (ICS.isUserDefined() && ICS.UserDefined.Before.First)
+ return ICS.UserDefined.Before.DeprecatedStringLiteralToCharPtr;
+ return false;
+}
+
/// 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).
@@ -3315,8 +3326,16 @@
// 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.
+
+ 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())
return ImplicitConversionSequence::Worse;
@@ -4227,6 +4246,7 @@
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
@@ -4301,6 +4321,7 @@
ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false;
ICS.Standard.ObjCLifetimeConversionBinding = ObjCLifetimeConversion;
ICS.Standard.CopyConstructor = 0;
+ ICS.Standard.DeprecatedStringLiteralToCharPtr = false;
return ICS;
}
@@ -4395,6 +4416,7 @@
ICS.Standard.BindsToRvalue = true;
ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false;
ICS.Standard.ObjCLifetimeConversionBinding = false;
+ ICS.Standard.DeprecatedStringLiteralToCharPtr = false;
} else if (ICS.isUserDefined()) {
// Don't allow rvalue references to bind to lvalues.
if (DeclType->isRValueReferenceType()) {
@@ -4483,6 +4505,7 @@
Result.Standard.setAsIdentityConversion();
Result.Standard.setFromType(ToType);
Result.Standard.setAllToTypes(ToType);
+ Result.Standard.DeprecatedStringLiteralToCharPtr = false;
}
Result.setStdInitializerListElement(toStdInitializerList);
@@ -4521,10 +4544,12 @@
// Initializer lists don't have a type.
Result.UserDefined.Before.setFromType(QualType());
Result.UserDefined.Before.setAllToTypes(QualType());
+ Result.UserDefined.Before.DeprecatedStringLiteralToCharPtr = false;
Result.UserDefined.After.setAsIdentityConversion();
Result.UserDefined.After.setFromType(ToType);
Result.UserDefined.After.setAllToTypes(ToType);
+ Result.UserDefined.After.DeprecatedStringLiteralToCharPtr = false;
Result.UserDefined.ConversionFunction = 0;
}
return Result;
@@ -4617,6 +4642,7 @@
Result.Standard.setAsIdentityConversion();
Result.Standard.setFromType(ToType);
Result.Standard.setAllToTypes(ToType);
+ Result.Standard.DeprecatedStringLiteralToCharPtr = false;
}
return Result;
}
@@ -4779,6 +4805,7 @@
ICS.Standard.BindsToRvalue = FromClassification.isRValue();
ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier
= (Method->getRefQualifier() == RQ_None);
+ ICS.Standard.DeprecatedStringLiteralToCharPtr = false;
return ICS;
}
Index: test/SemaCXX/cxx0x-type-convert-construct.cpp
===================================================================
--- test/SemaCXX/cxx0x-type-convert-construct.cpp
+++ test/SemaCXX/cxx0x-type-convert-construct.cpp
@@ -9,9 +9,9 @@
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{{conversion from string literal to 'char *' is ill-formed in C++11}}
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{{conversion from string literal to 'wchar_t *' is ill-formed in C++11}}
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;
Index: test/SemaCXX/deprecated.cpp
===================================================================
--- test/SemaCXX/deprecated.cpp
+++ test/SemaCXX/deprecated.cpp
@@ -24,12 +24,15 @@
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 {{conversion from string literal to 'char *' is ill-formed in C++11}}
+#endif
}
struct S { int n; };
Index: test/SemaCXX/overload-0x.cpp
===================================================================
--- test/SemaCXX/overload-0x.cpp
+++ test/SemaCXX/overload-0x.cpp
@@ -1,5 +1,8 @@
// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
+// RUN: %clang_cc1 -DCHECK_BEST -std=c++11 -S -emit-llvm -o - %s | FileCheck %s --check-prefix=CXX11
+// RUN: %clang_cc1 -DCHECK_BEST -S -emit-llvm -o - %s | FileCheck %s --check-prefix=CXX03
+#ifndef CHECK_BEST
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}}
A &operator=(void*); // expected-note {{candidate function not viable: 'this' argument has type 'const test0::A', but method is not marked const}}
@@ -9,3 +12,47 @@
a = "help"; // expected-error {{no viable overloaded '='}}
}
}
+#endif
+
+namespace PR16314 {
+ void f(char*);
+ int &f(...);
+ void x()
+ {
+ // CXX03: call void @_ZN7PR163141fEPc
+ // CXX11: call i32* (...)* @_ZN7PR163141fEz
+ f("foo");
+#if __cplusplus < 201103L
+ // expected-warning@-2 {{warning: conversion from string literal to 'char *' is deprecated}}
+#endif
+ }
+}
+
+namespace warn_if_best {
+ void f(char *);
+ void f(double);
+ void x()
+ {
+ // CXX11: call void @_ZN12warn_if_best1fEPc
+ // CXX03: call void @_ZN12warn_if_best1fEPc
+ f("foo");
+#if __cplusplus >= 201103L
+ // expected-warning@-2 {{conversion from string literal to 'char *' is ill-formed in C++11}}
+#else
+ // expected-warning@-4 {{warning: conversion from string literal to 'char *' is deprecated}}
+#endif
+ }
+}
+
+namespace userdefined_vs_illformed {
+ struct X { X(const char *); };
+
+ void f(char *p);
+ void f(X x);
+ void g()
+ {
+ // CXX11: call void @_ZN24userdefined_vs_illformed1fENS_1XE
+ // CXX03: call void @_ZN24userdefined_vs_illformed1fEPc
+ f("foo");
+ }
+}
Index: unittests/ASTMatchers/ASTMatchersTest.cpp
===================================================================
--- unittests/ASTMatchers/ASTMatchersTest.cpp
+++ unittests/ASTMatchers/ASTMatchersTest.cpp
@@ -2608,13 +2608,13 @@
}
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()));
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits