diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index 60220834dba6..b234d56fa013 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -766,7 +766,8 @@ public: bool SuppressUserConversions, bool AllowExplicit, bool ForceRValue, - bool InOverloadResolution); + bool InOverloadResolution, + bool UserCast = false); bool IsStandardConversion(Expr *From, QualType ToType, bool InOverloadResolution, StandardConversionSequence& SCS); @@ -790,7 +791,8 @@ public: UserDefinedConversionSequence& User, OverloadCandidateSet& Conversions, bool AllowConversionFunctions, - bool AllowExplicit, bool ForceRValue); + bool AllowExplicit, bool ForceRValue, + bool UserCast = false); bool DiagnoseAmbiguousUserDefinedConversion(Expr *From, QualType ToType); diff --git a/clang/lib/Sema/SemaCXXCast.cpp b/clang/lib/Sema/SemaCXXCast.cpp index e5c4390752c9..9822a44b0f8e 100644 --- a/clang/lib/Sema/SemaCXXCast.cpp +++ b/clang/lib/Sema/SemaCXXCast.cpp @@ -806,7 +806,8 @@ TryStaticImplicitCast(Sema &Self, Expr *SrcExpr, QualType DestType, /*SuppressUserConversions=*/false, /*AllowExplicit=*/true, /*ForceRValue=*/false, - /*InOverloadResolution=*/false); + /*InOverloadResolution=*/false, + /*one of user provided casts*/true); if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion) return TC_NotApplicable; diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 6966926e9e92..18614f787096 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -404,11 +404,14 @@ Sema::IsOverload(FunctionDecl *New, Decl* OldD, /// permitted. /// If @p ForceRValue, then overloading is performed as if From was an rvalue, /// no matter its actual lvalueness. +/// If @p UserCast, the implicit conversion is being done for a user-specified +/// cast. ImplicitConversionSequence Sema::TryImplicitConversion(Expr* From, QualType ToType, bool SuppressUserConversions, bool AllowExplicit, bool ForceRValue, - bool InOverloadResolution) { + bool InOverloadResolution, + bool UserCast) { ImplicitConversionSequence ICS; OverloadCandidateSet Conversions; OverloadingResult UserDefResult = OR_Success; @@ -419,7 +422,7 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType, ICS.UserDefined, Conversions, !SuppressUserConversions, AllowExplicit, - ForceRValue)) == OR_Success) { + ForceRValue, UserCast)) == OR_Success) { ICS.ConversionKind = ImplicitConversionSequence::UserDefinedConversion; // C++ [over.ics.user]p4: // A conversion of an expression of class type to the same class @@ -1372,12 +1375,15 @@ static void GetFunctionAndTemplate(AnyFunctionDecl Orig, T *&Function, /// /// \param ForceRValue true if the expression should be treated as an rvalue /// for overload resolution. +/// \param UserCast true if looking for user defined conversion for a static +/// cast. Sema::OverloadingResult Sema::IsUserDefinedConversion( Expr *From, QualType ToType, UserDefinedConversionSequence& User, OverloadCandidateSet& CandidateSet, bool AllowConversionFunctions, - bool AllowExplicit, bool ForceRValue) { + bool AllowExplicit, bool ForceRValue, + bool UserCast) { if (const RecordType *ToRecordType = ToType->getAs()) { if (CXXRecordDecl *ToRecordDecl = dyn_cast(ToRecordType->getDecl())) { @@ -1411,11 +1417,14 @@ Sema::OverloadingResult Sema::IsUserDefinedConversion( if (ConstructorTmpl) AddTemplateOverloadCandidate(ConstructorTmpl, false, 0, 0, &From, 1, CandidateSet, - /*SuppressUserConversions=*/true, + /*SuppressUserConversions=*/!UserCast, ForceRValue); else + // Allow one user-defined conversion when user specifies a + // From->ToType conversion via an static cast (c-style, etc). AddOverloadCandidate(Constructor, &From, 1, CandidateSet, - /*SuppressUserConversions=*/true, ForceRValue); + /*SuppressUserConversions=*/!UserCast, + ForceRValue); } } } diff --git a/clang/test/CodeGenCXX/cast-conversion.cpp b/clang/test/CodeGenCXX/cast-conversion.cpp new file mode 100644 index 000000000000..f571f549d094 --- /dev/null +++ b/clang/test/CodeGenCXX/cast-conversion.cpp @@ -0,0 +1,33 @@ +// RUN: clang-cc -triple x86_64-apple-darwin -std=c++0x -S %s -o %t-64.s && +// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s && +// RUN: clang-cc -triple i386-apple-darwin -std=c++0x -S %s -o %t-32.s && +// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s && +// RUN: true + +struct A { + A(int); +}; + +struct B { + B(A); +}; + +int main () { + (B)10; + B(10); + static_cast(10); +} + +// CHECK-LP64: call __ZN1AC1Ei +// CHECK-LP64: call __ZN1BC1E1A +// CHECK-LP64: call __ZN1AC1Ei +// CHECK-LP64: call __ZN1BC1E1A +// CHECK-LP64: call __ZN1AC1Ei +// CHECK-LP64: call __ZN1BC1E1A + +// CHECK-LP32: call L__ZN1AC1Ei +// CHECK-LP32: call L__ZN1BC1E1A +// CHECK-LP32: call L__ZN1AC1Ei +// CHECK-LP32: call L__ZN1BC1E1A +// CHECK-LP32: call L__ZN1AC1Ei +// CHECK-LP32: call L__ZN1BC1E1A diff --git a/clang/test/SemaCXX/cast-conversion.cpp b/clang/test/SemaCXX/cast-conversion.cpp new file mode 100644 index 000000000000..cbc24aef28d5 --- /dev/null +++ b/clang/test/SemaCXX/cast-conversion.cpp @@ -0,0 +1,21 @@ +// RUN: clang-cc -fsyntax-only -verify %s -std=c++0x + +struct R { + R(int); +}; + +struct A { + A(R); +}; + +struct B { + B(A); +}; + +int main () { + B(10); // expected-error {{functional-style cast from 'int' to 'struct B' is not allowed}} + (B)10; // expected-error {{C-style cast from 'int' to 'struct B' is not allowed}} + static_cast(10); // expected-error {{static_cast from 'int' to 'struct B' is not allowed}} \\ + // expected-warning {{expression result unused}} +} +