Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -4490,6 +4490,10 @@ InGroup>, DefaultError; def warn_deprecated_string_literal_conversion : Warning< "conversion from string literal to %0 is deprecated">, InGroup; +def ext_deprecated_string_literal_conversion : ExtWarn< + "conversion from string literal to %0 is ill-formed in C++11">, InGroup; +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, 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()->getPointeeType()); User.After.setAllToTypes(ToType); + User.After.DeprecatedStringLiteralToCharPtr = false; return OR_Success; } @@ -3176,6 +3180,7 @@ if (isa(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()->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(Function1); if (!Conv1) return ImplicitConversionSequence::Indistinguishable; - + CXXConversionDecl *Conv2 = dyn_cast(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()));