From 097e0a2cb08c8244a6923489acc8f890e6a99b59 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Tue, 21 May 2013 19:05:48 +0000 Subject: [PATCH] Refactor places which perform contextual implicit conversions to go through a common function. The C++1y contextual implicit conversion rules themselves are not yet implemented, however. This also fixes a subtle bug where template instantiation context notes were dropped for diagnostics coming from conversions for integral constant expressions -- we were implicitly slicing a SemaDiagnosticBuilder into a DiagnosticBuilder when producing these diagnostics, and losing their context notes in the process. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@182406 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticSemaKinds.td | 8 +- include/clang/Sema/Sema.h | 86 +++++++---- lib/Sema/SemaExpr.cpp | 150 ++++++------------- lib/Sema/SemaExprCXX.cpp | 162 +++++++++++---------- lib/Sema/SemaOverload.cpp | 83 +++++------ lib/Sema/SemaStmt.cpp | 40 +++-- test/SemaCXX/conversion-delete-expr.cpp | 24 +-- test/SemaCXX/explicit.cpp | 4 +- test/SemaCXX/new-delete.cpp | 4 +- test/SemaCXX/switch.cpp | 15 ++ 10 files changed, 283 insertions(+), 293 deletions(-) diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index f52d1f3162..e12851dc53 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -4759,13 +4759,17 @@ def err_default_init_const : Error< def err_delete_operand : Error<"cannot delete expression of type %0">; def ext_delete_void_ptr_operand : ExtWarn< "cannot delete expression with pointer-to-'void' type %0">; -def err_ambiguous_delete_operand : Error<"ambiguous conversion of delete " - "expression of type %0 to a pointer">; +def err_ambiguous_delete_operand : Error< + "ambiguous conversion of delete expression of type %0 to a pointer">; def warn_delete_incomplete : Warning< "deleting pointer to incomplete type %0 may cause undefined behavior">, InGroup>; def err_delete_incomplete_class_type : Error< "deleting incomplete class type %0; no conversions to pointer type">; +def err_delete_explicit_conversion : Error< + "converting delete expression from type %0 to type %1 invokes an explicit " + "conversion function">; +def note_delete_conversion : Note<"conversion to pointer type %0">; def warn_delete_array_type : Warning< "'delete' applied to a pointer-to-array type %0 treated as delete[]">; def err_no_suitable_delete_member_function_found : Error< diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index a2e47e5a5a..69ef5f9cc2 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -906,6 +906,15 @@ public: // Dispatch to Sema to emit the diagnostic. SemaRef.EmitCurrentDiagnostic(DiagID); } + + /// Teach operator<< to produce an object of the correct type. + template + friend const SemaDiagnosticBuilder &operator<<( + const SemaDiagnosticBuilder &Diag, const T &Value) { + const DiagnosticBuilder &BaseDiag = Diag; + BaseDiag << Value; + return Diag; + } }; /// \brief Emit a diagnostic. @@ -1928,58 +1937,83 @@ public: ExprResult CheckConvertedConstantExpression(Expr *From, QualType T, llvm::APSInt &Value, CCEKind CCE); - /// \brief Abstract base class used to diagnose problems that occur while - /// trying to convert an expression to integral or enumeration type. - class ICEConvertDiagnoser { + /// \brief Abstract base class used to perform a contextual implicit + /// conversion from an expression to any type passing a filter. + class ContextualImplicitConverter { public: bool Suppress; bool SuppressConversion; - ICEConvertDiagnoser(bool Suppress = false, - bool SuppressConversion = false) - : Suppress(Suppress), SuppressConversion(SuppressConversion) { } + ContextualImplicitConverter(bool Suppress = false, + bool SuppressConversion = false) + : Suppress(Suppress), SuppressConversion(SuppressConversion) {} + + /// \brief Determine whether the specified type is a valid destination type + /// for this conversion. + virtual bool match(QualType T) = 0; /// \brief Emits a diagnostic complaining that the expression does not have /// integral or enumeration type. - virtual DiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc, - QualType T) = 0; + virtual SemaDiagnosticBuilder + diagnoseNoMatch(Sema &S, SourceLocation Loc, QualType T) = 0; /// \brief Emits a diagnostic when the expression has incomplete class type. - virtual DiagnosticBuilder diagnoseIncomplete(Sema &S, SourceLocation Loc, - QualType T) = 0; + virtual SemaDiagnosticBuilder + diagnoseIncomplete(Sema &S, SourceLocation Loc, QualType T) = 0; /// \brief Emits a diagnostic when the only matching conversion function /// is explicit. - virtual DiagnosticBuilder diagnoseExplicitConv(Sema &S, SourceLocation Loc, - QualType T, - QualType ConvTy) = 0; + virtual SemaDiagnosticBuilder diagnoseExplicitConv( + Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) = 0; /// \brief Emits a note for the explicit conversion function. - virtual DiagnosticBuilder + virtual SemaDiagnosticBuilder noteExplicitConv(Sema &S, CXXConversionDecl *Conv, QualType ConvTy) = 0; /// \brief Emits a diagnostic when there are multiple possible conversion /// functions. - virtual DiagnosticBuilder diagnoseAmbiguous(Sema &S, SourceLocation Loc, - QualType T) = 0; + virtual SemaDiagnosticBuilder + diagnoseAmbiguous(Sema &S, SourceLocation Loc, QualType T) = 0; /// \brief Emits a note for one of the candidate conversions. - virtual DiagnosticBuilder noteAmbiguous(Sema &S, CXXConversionDecl *Conv, - QualType ConvTy) = 0; + virtual SemaDiagnosticBuilder + noteAmbiguous(Sema &S, CXXConversionDecl *Conv, QualType ConvTy) = 0; /// \brief Emits a diagnostic when we picked a conversion function /// (for cases when we are not allowed to pick a conversion function). - virtual DiagnosticBuilder diagnoseConversion(Sema &S, SourceLocation Loc, - QualType T, - QualType ConvTy) = 0; + virtual SemaDiagnosticBuilder diagnoseConversion( + Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) = 0; - virtual ~ICEConvertDiagnoser() {} + virtual ~ContextualImplicitConverter() {} }; - ExprResult - ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *FromE, - ICEConvertDiagnoser &Diagnoser, - bool AllowScopedEnumerations); + class ICEConvertDiagnoser : public ContextualImplicitConverter { + bool AllowScopedEnumerations; + + public: + ICEConvertDiagnoser(bool AllowScopedEnumerations, + bool Suppress, bool SuppressConversion) + : ContextualImplicitConverter(Suppress, SuppressConversion), + AllowScopedEnumerations(AllowScopedEnumerations) {} + + /// Match an integral or (possibly scoped) enumeration type. + bool match(QualType T); + + SemaDiagnosticBuilder + diagnoseNoMatch(Sema &S, SourceLocation Loc, QualType T) { + return diagnoseNotInt(S, Loc, T); + } + + /// \brief Emits a diagnostic complaining that the expression does not have + /// integral or enumeration type. + virtual SemaDiagnosticBuilder + diagnoseNotInt(Sema &S, SourceLocation Loc, QualType T) = 0; + }; + + /// Perform a contextual implicit conversion. + ExprResult PerformContextualImplicitConversion( + SourceLocation Loc, Expr *FromE, ContextualImplicitConverter &Converter); + enum ObjCSubscriptKind { OS_Array, diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 67c4f3e7dd..87bc673adf 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -10391,112 +10391,52 @@ Sema::VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result, // have a single non-explicit conversion function to an integral or // unscoped enumeration type ExprResult Converted; - if (!Diagnoser.Suppress) { - class CXX11ConvertDiagnoser : public ICEConvertDiagnoser { - public: - CXX11ConvertDiagnoser() : ICEConvertDiagnoser(false, true) { } - - virtual DiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc, - QualType T) { - return S.Diag(Loc, diag::err_ice_not_integral) << T; - } - - virtual DiagnosticBuilder diagnoseIncomplete(Sema &S, - SourceLocation Loc, - QualType T) { - return S.Diag(Loc, diag::err_ice_incomplete_type) << T; - } - - virtual DiagnosticBuilder diagnoseExplicitConv(Sema &S, - SourceLocation Loc, - QualType T, - QualType ConvTy) { - return S.Diag(Loc, diag::err_ice_explicit_conversion) << T << ConvTy; - } - - virtual DiagnosticBuilder noteExplicitConv(Sema &S, - CXXConversionDecl *Conv, - QualType ConvTy) { - return S.Diag(Conv->getLocation(), diag::note_ice_conversion_here) - << ConvTy->isEnumeralType() << ConvTy; - } - - virtual DiagnosticBuilder diagnoseAmbiguous(Sema &S, SourceLocation Loc, - QualType T) { - return S.Diag(Loc, diag::err_ice_ambiguous_conversion) << T; - } - - virtual DiagnosticBuilder noteAmbiguous(Sema &S, - CXXConversionDecl *Conv, - QualType ConvTy) { - return S.Diag(Conv->getLocation(), diag::note_ice_conversion_here) - << ConvTy->isEnumeralType() << ConvTy; - } - - virtual DiagnosticBuilder diagnoseConversion(Sema &S, - SourceLocation Loc, - QualType T, - QualType ConvTy) { - return DiagnosticBuilder::getEmpty(); - } - } ConvertDiagnoser; + class CXX11ConvertDiagnoser : public ICEConvertDiagnoser { + public: + CXX11ConvertDiagnoser(bool Silent) + : ICEConvertDiagnoser(/*AllowScopedEnumerations*/false, + Silent, true) {} - Converted = ConvertToIntegralOrEnumerationType(DiagLoc, E, - ConvertDiagnoser, - /*AllowScopedEnumerations*/ false); - } else { - // The caller wants to silently enquire whether this is an ICE. Don't - // produce any diagnostics if it isn't. - class SilentICEConvertDiagnoser : public ICEConvertDiagnoser { - public: - SilentICEConvertDiagnoser() : ICEConvertDiagnoser(true, true) { } - - virtual DiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc, - QualType T) { - return DiagnosticBuilder::getEmpty(); - } - - virtual DiagnosticBuilder diagnoseIncomplete(Sema &S, - SourceLocation Loc, - QualType T) { - return DiagnosticBuilder::getEmpty(); - } - - virtual DiagnosticBuilder diagnoseExplicitConv(Sema &S, - SourceLocation Loc, - QualType T, - QualType ConvTy) { - return DiagnosticBuilder::getEmpty(); - } - - virtual DiagnosticBuilder noteExplicitConv(Sema &S, - CXXConversionDecl *Conv, - QualType ConvTy) { - return DiagnosticBuilder::getEmpty(); - } - - virtual DiagnosticBuilder diagnoseAmbiguous(Sema &S, SourceLocation Loc, - QualType T) { - return DiagnosticBuilder::getEmpty(); - } - - virtual DiagnosticBuilder noteAmbiguous(Sema &S, - CXXConversionDecl *Conv, - QualType ConvTy) { - return DiagnosticBuilder::getEmpty(); - } - - virtual DiagnosticBuilder diagnoseConversion(Sema &S, - SourceLocation Loc, - QualType T, - QualType ConvTy) { - return DiagnosticBuilder::getEmpty(); - } - } ConvertDiagnoser; - - Converted = ConvertToIntegralOrEnumerationType(DiagLoc, E, - ConvertDiagnoser, false); - } + virtual SemaDiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc, + QualType T) { + return S.Diag(Loc, diag::err_ice_not_integral) << T; + } + + virtual SemaDiagnosticBuilder diagnoseIncomplete( + Sema &S, SourceLocation Loc, QualType T) { + return S.Diag(Loc, diag::err_ice_incomplete_type) << T; + } + + virtual SemaDiagnosticBuilder diagnoseExplicitConv( + Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) { + return S.Diag(Loc, diag::err_ice_explicit_conversion) << T << ConvTy; + } + + virtual SemaDiagnosticBuilder noteExplicitConv( + Sema &S, CXXConversionDecl *Conv, QualType ConvTy) { + return S.Diag(Conv->getLocation(), diag::note_ice_conversion_here) + << ConvTy->isEnumeralType() << ConvTy; + } + + virtual SemaDiagnosticBuilder diagnoseAmbiguous( + Sema &S, SourceLocation Loc, QualType T) { + return S.Diag(Loc, diag::err_ice_ambiguous_conversion) << T; + } + + virtual SemaDiagnosticBuilder noteAmbiguous( + Sema &S, CXXConversionDecl *Conv, QualType ConvTy) { + return S.Diag(Conv->getLocation(), diag::note_ice_conversion_here) + << ConvTy->isEnumeralType() << ConvTy; + } + + virtual SemaDiagnosticBuilder diagnoseConversion( + Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) { + llvm_unreachable("conversion functions are permitted"); + } + } ConvertDiagnoser(Diagnoser.Suppress); + + Converted = PerformContextualImplicitConversion(DiagLoc, E, + ConvertDiagnoser); if (Converted.isInvalid()) return Converted; E = Converted.take(); diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index cde2e4940b..1d2a554ea2 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -1180,54 +1180,53 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, // C++11 [expr.new]p6: The expression [...] shall be of integral or unscoped // enumeration type, or a class type for which a single non-explicit // conversion function to integral or unscoped enumeration type exists. + // C++1y [expr.new]p6: The expression [...] is implicitly converted to + // std::size_t. (FIXME) if (ArraySize && !ArraySize->isTypeDependent()) { class SizeConvertDiagnoser : public ICEConvertDiagnoser { Expr *ArraySize; - + public: SizeConvertDiagnoser(Expr *ArraySize) - : ICEConvertDiagnoser(false, false), ArraySize(ArraySize) { } - - virtual DiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc, - QualType T) { + : ICEConvertDiagnoser(/*AllowScopedEnumerations*/false, false, false), + ArraySize(ArraySize) {} + + virtual SemaDiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc, + QualType T) { return S.Diag(Loc, diag::err_array_size_not_integral) << S.getLangOpts().CPlusPlus11 << T; } - - virtual DiagnosticBuilder diagnoseIncomplete(Sema &S, SourceLocation Loc, - QualType T) { + + virtual SemaDiagnosticBuilder diagnoseIncomplete( + Sema &S, SourceLocation Loc, QualType T) { return S.Diag(Loc, diag::err_array_size_incomplete_type) << T << ArraySize->getSourceRange(); } - - virtual DiagnosticBuilder diagnoseExplicitConv(Sema &S, - SourceLocation Loc, - QualType T, - QualType ConvTy) { + + virtual SemaDiagnosticBuilder diagnoseExplicitConv( + Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) { return S.Diag(Loc, diag::err_array_size_explicit_conversion) << T << ConvTy; } - - virtual DiagnosticBuilder noteExplicitConv(Sema &S, - CXXConversionDecl *Conv, - QualType ConvTy) { + + virtual SemaDiagnosticBuilder noteExplicitConv( + Sema &S, CXXConversionDecl *Conv, QualType ConvTy) { return S.Diag(Conv->getLocation(), diag::note_array_size_conversion) << ConvTy->isEnumeralType() << ConvTy; } - - virtual DiagnosticBuilder diagnoseAmbiguous(Sema &S, SourceLocation Loc, - QualType T) { + + virtual SemaDiagnosticBuilder diagnoseAmbiguous( + Sema &S, SourceLocation Loc, QualType T) { return S.Diag(Loc, diag::err_array_size_ambiguous_conversion) << T; } - - virtual DiagnosticBuilder noteAmbiguous(Sema &S, CXXConversionDecl *Conv, - QualType ConvTy) { + + virtual SemaDiagnosticBuilder noteAmbiguous( + Sema &S, CXXConversionDecl *Conv, QualType ConvTy) { return S.Diag(Conv->getLocation(), diag::note_array_size_conversion) << ConvTy->isEnumeralType() << ConvTy; } - - virtual DiagnosticBuilder diagnoseConversion(Sema &S, SourceLocation Loc, - QualType T, - QualType ConvTy) { + + virtual SemaDiagnosticBuilder diagnoseConversion( + Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) { return S.Diag(Loc, S.getLangOpts().CPlusPlus11 ? diag::warn_cxx98_compat_array_size_conversion @@ -1237,8 +1236,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, } SizeDiagnoser(ArraySize); ExprResult ConvertedSize - = ConvertToIntegralOrEnumerationType(StartLoc, ArraySize, SizeDiagnoser, - /*AllowScopedEnumerations*/ false); + = PerformContextualImplicitConversion(StartLoc, ArraySize, SizeDiagnoser); if (ConvertedSize.isInvalid()) return ExprError(); @@ -2054,7 +2052,8 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, bool ArrayForm, Expr *ExE) { // C++ [expr.delete]p1: // The operand shall have a pointer type, or a class type having a single - // conversion function to a pointer type. The result has type void. + // non-explicit conversion function to a pointer type. The result has type + // void. // // DR599 amends "pointer type" to "pointer to object type" in both cases. @@ -2071,59 +2070,65 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, QualType Type = Ex.get()->getType(); - if (const RecordType *Record = Type->getAs()) { - if (RequireCompleteType(StartLoc, Type, - diag::err_delete_incomplete_class_type)) - return ExprError(); + class DeleteConverter : public ContextualImplicitConverter { + public: + DeleteConverter() : ContextualImplicitConverter(false, true) {} - SmallVector ObjectPtrConversions; - - CXXRecordDecl *RD = cast(Record->getDecl()); - std::pair - Conversions = RD->getVisibleConversionFunctions(); - for (CXXRecordDecl::conversion_iterator - I = Conversions.first, E = Conversions.second; I != E; ++I) { - NamedDecl *D = I.getDecl(); - if (isa(D)) - D = cast(D)->getTargetDecl(); - - // Skip over templated conversion functions; they aren't considered. - if (isa(D)) - continue; - - CXXConversionDecl *Conv = cast(D); - - QualType ConvType = Conv->getConversionType().getNonReferenceType(); + bool match(QualType ConvType) { + // FIXME: If we have an operator T* and an operator void*, we must pick + // the operator T*. if (const PointerType *ConvPtrType = ConvType->getAs()) if (ConvPtrType->getPointeeType()->isIncompleteOrObjectType()) - ObjectPtrConversions.push_back(Conv); + return true; + return false; } - if (ObjectPtrConversions.size() == 1) { - // We have a single conversion to a pointer-to-object type. Perform - // that conversion. - // TODO: don't redo the conversion calculation. - ExprResult Res = - PerformImplicitConversion(Ex.get(), - ObjectPtrConversions.front()->getConversionType(), - AA_Converting); - if (Res.isUsable()) { - Ex = Res; - Type = Ex.get()->getType(); - } - } - else if (ObjectPtrConversions.size() > 1) { - Diag(StartLoc, diag::err_ambiguous_delete_operand) - << Type << Ex.get()->getSourceRange(); - for (unsigned i= 0; i < ObjectPtrConversions.size(); i++) - NoteOverloadCandidate(ObjectPtrConversions[i]); - return ExprError(); - } - } - if (!Type->isPointerType()) - return ExprError(Diag(StartLoc, diag::err_delete_operand) - << Type << Ex.get()->getSourceRange()); + SemaDiagnosticBuilder diagnoseNoMatch(Sema &S, SourceLocation Loc, + QualType T) { + return S.Diag(Loc, diag::err_delete_operand) << T; + } + + SemaDiagnosticBuilder diagnoseIncomplete(Sema &S, SourceLocation Loc, + QualType T) { + return S.Diag(Loc, diag::err_delete_incomplete_class_type) << T; + } + + SemaDiagnosticBuilder diagnoseExplicitConv(Sema &S, SourceLocation Loc, + QualType T, QualType ConvTy) { + return S.Diag(Loc, diag::err_delete_explicit_conversion) << T << ConvTy; + } + + SemaDiagnosticBuilder noteExplicitConv(Sema &S, CXXConversionDecl *Conv, + QualType ConvTy) { + return S.Diag(Conv->getLocation(), diag::note_delete_conversion) + << ConvTy; + } + + SemaDiagnosticBuilder diagnoseAmbiguous(Sema &S, SourceLocation Loc, + QualType T) { + return S.Diag(Loc, diag::err_ambiguous_delete_operand) << T; + } + + SemaDiagnosticBuilder noteAmbiguous(Sema &S, CXXConversionDecl *Conv, + QualType ConvTy) { + return S.Diag(Conv->getLocation(), diag::note_delete_conversion) + << ConvTy; + } + + SemaDiagnosticBuilder diagnoseConversion(Sema &S, SourceLocation Loc, + QualType T, QualType ConvTy) { + llvm_unreachable("conversion functions are permitted"); + } + } Converter; + + Ex = PerformContextualImplicitConversion(StartLoc, Ex.take(), Converter); + if (Ex.isInvalid()) + return ExprError(); + Type = Ex.get()->getType(); + if (!Converter.match(Type)) + // FIXME: PerformContextualImplicitConversion should return ExprError + // itself in this case. + return ExprError(); QualType Pointee = Type->getAs()->getPointeeType(); QualType PointeeElem = Context.getBaseElementType(Pointee); @@ -2246,7 +2251,6 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, PDiag(diag::err_access_dtor) << PointeeElem); } } - } return Owned(new (Context) CXXDeleteExpr(Context.VoidTy, UseGlobal, ArrayForm, diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index dbe151c782..034790db20 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -5116,34 +5116,31 @@ ExprResult Sema::PerformContextuallyConvertToObjCPointer(Expr *From) { /// Determine whether the provided type is an integral type, or an enumeration /// type of a permitted flavor. -static bool isIntegralOrEnumerationType(QualType T, bool AllowScopedEnum) { - return AllowScopedEnum ? T->isIntegralOrEnumerationType() - : T->isIntegralOrUnscopedEnumerationType(); +bool Sema::ICEConvertDiagnoser::match(QualType T) { + return AllowScopedEnumerations ? T->isIntegralOrEnumerationType() + : T->isIntegralOrUnscopedEnumerationType(); } -/// \brief Attempt to convert the given expression to an integral or -/// enumeration type. +/// \brief Attempt to convert the given expression to a type which is accepted +/// by the given converter. /// -/// This routine will attempt to convert an expression of class type to an -/// integral or enumeration type, if that class type only has a single -/// conversion to an integral or enumeration type. +/// This routine will attempt to convert an expression of class type to a +/// type accepted by the specified converter. In C++11 and before, the class +/// must have a single non-explicit conversion function converting to a matching +/// type. In C++1y, there can be multiple such conversion functions, but only +/// one target type. /// /// \param Loc The source location of the construct that requires the /// conversion. /// /// \param From The expression we're converting from. /// -/// \param Diagnoser Used to output any diagnostics. -/// -/// \param AllowScopedEnumerations Specifies whether conversions to scoped -/// enumerations should be considered. +/// \param Converter Used to control and diagnose the conversion process. /// /// \returns The expression, converted to an integral or enumeration type if /// successful. -ExprResult -Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From, - ICEConvertDiagnoser &Diagnoser, - bool AllowScopedEnumerations) { +ExprResult Sema::PerformContextualImplicitConversion( + SourceLocation Loc, Expr *From, ContextualImplicitConverter &Converter) { // We can't perform any more checking for type-dependent expressions. if (From->isTypeDependent()) return Owned(From); @@ -5155,34 +5152,34 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From, From = result.take(); } - // If the expression already has integral or enumeration type, we're golden. + // If the expression already has a matching type, we're golden. QualType T = From->getType(); - if (isIntegralOrEnumerationType(T, AllowScopedEnumerations)) + if (Converter.match(T)) return DefaultLvalueConversion(From); // FIXME: Check for missing '()' if T is a function type? - // If we don't have a class type in C++, there's no way we can get an - // expression of integral or enumeration type. + // We can only perform contextual implicit conversions on objects of class + // type. const RecordType *RecordTy = T->getAs(); if (!RecordTy || !getLangOpts().CPlusPlus) { - if (!Diagnoser.Suppress) - Diagnoser.diagnoseNotInt(*this, Loc, T) << From->getSourceRange(); + if (!Converter.Suppress) + Converter.diagnoseNoMatch(*this, Loc, T) << From->getSourceRange(); return Owned(From); } // We must have a complete class type. struct TypeDiagnoserPartialDiag : TypeDiagnoser { - ICEConvertDiagnoser &Diagnoser; + ContextualImplicitConverter &Converter; Expr *From; - - TypeDiagnoserPartialDiag(ICEConvertDiagnoser &Diagnoser, Expr *From) - : TypeDiagnoser(Diagnoser.Suppress), Diagnoser(Diagnoser), From(From) {} - + + TypeDiagnoserPartialDiag(ContextualImplicitConverter &Converter, Expr *From) + : TypeDiagnoser(Converter.Suppress), Converter(Converter), From(From) {} + virtual void diagnose(Sema &S, SourceLocation Loc, QualType T) { - Diagnoser.diagnoseIncomplete(S, Loc, T) << From->getSourceRange(); + Converter.diagnoseIncomplete(S, Loc, T) << From->getSourceRange(); } - } IncompleteDiagnoser(Diagnoser, From); + } IncompleteDiagnoser(Converter, From); if (RequireCompleteType(Loc, T, IncompleteDiagnoser)) return Owned(From); @@ -5201,9 +5198,8 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From, I = Conversions.first, E = Conversions.second; I != E; ++I) { if (CXXConversionDecl *Conversion = dyn_cast((*I)->getUnderlyingDecl())) { - if (isIntegralOrEnumerationType( - Conversion->getConversionType().getNonReferenceType(), - AllowScopedEnumerations)) { + if (Converter.match( + Conversion->getConversionType().getNonReferenceType())) { if (Conversion->isExplicit()) ExplicitConversions.addDecl(I.getDecl(), I.getAccess()); else @@ -5212,9 +5208,10 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From, } } + // FIXME: Implement the C++11 rules! switch (ViableConversions.size()) { case 0: - if (ExplicitConversions.size() == 1 && !Diagnoser.Suppress) { + if (ExplicitConversions.size() == 1 && !Converter.Suppress) { DeclAccessPair Found = ExplicitConversions[0]; CXXConversionDecl *Conversion = cast(Found->getUnderlyingDecl()); @@ -5226,12 +5223,12 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From, std::string TypeStr; ConvTy.getAsStringInternal(TypeStr, getPrintingPolicy()); - Diagnoser.diagnoseExplicitConv(*this, Loc, T, ConvTy) + Converter.diagnoseExplicitConv(*this, Loc, T, ConvTy) << FixItHint::CreateInsertion(From->getLocStart(), "static_cast<" + TypeStr + ">(") << FixItHint::CreateInsertion(PP.getLocForEndOfToken(From->getLocEnd()), ")"); - Diagnoser.noteExplicitConv(*this, Conversion, ConvTy); + Converter.noteExplicitConv(*this, Conversion, ConvTy); // If we aren't in a SFINAE context, build a call to the // explicit conversion function. @@ -5262,11 +5259,11 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From, = cast(Found->getUnderlyingDecl()); QualType ConvTy = Conversion->getConversionType().getNonReferenceType(); - if (!Diagnoser.SuppressConversion) { + if (!Converter.SuppressConversion) { if (isSFINAEContext()) return ExprError(); - Diagnoser.diagnoseConversion(*this, Loc, T, ConvTy) + Converter.diagnoseConversion(*this, Loc, T, ConvTy) << From->getSourceRange(); } @@ -5283,24 +5280,22 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From, } default: - if (Diagnoser.Suppress) + if (Converter.Suppress) return ExprError(); - Diagnoser.diagnoseAmbiguous(*this, Loc, T) << From->getSourceRange(); + Converter.diagnoseAmbiguous(*this, Loc, T) << From->getSourceRange(); for (unsigned I = 0, N = ViableConversions.size(); I != N; ++I) { CXXConversionDecl *Conv = cast(ViableConversions[I]->getUnderlyingDecl()); QualType ConvTy = Conv->getConversionType().getNonReferenceType(); - Diagnoser.noteAmbiguous(*this, Conv, ConvTy); + Converter.noteAmbiguous(*this, Conv, ConvTy); } return Owned(From); } - if (!isIntegralOrEnumerationType(From->getType(), AllowScopedEnumerations) && - !Diagnoser.Suppress) { - Diagnoser.diagnoseNotInt(*this, Loc, From->getType()) + if (!Converter.match(From->getType()) && !Converter.Suppress) + Converter.diagnoseNoMatch(*this, Loc, From->getType()) << From->getSourceRange(); - } return DefaultLvalueConversion(From); } diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 3cd1a11ba5..03af4f1f39 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -592,52 +592,50 @@ Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, Expr *Cond, public: SwitchConvertDiagnoser(Expr *Cond) - : ICEConvertDiagnoser(false, true), Cond(Cond) { } + : ICEConvertDiagnoser(/*AllowScopedEnumerations*/true, false, true), + Cond(Cond) {} - virtual DiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc, - QualType T) { + virtual SemaDiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc, + QualType T) { return S.Diag(Loc, diag::err_typecheck_statement_requires_integer) << T; } - virtual DiagnosticBuilder diagnoseIncomplete(Sema &S, SourceLocation Loc, - QualType T) { + virtual SemaDiagnosticBuilder diagnoseIncomplete( + Sema &S, SourceLocation Loc, QualType T) { return S.Diag(Loc, diag::err_switch_incomplete_class_type) << T << Cond->getSourceRange(); } - virtual DiagnosticBuilder diagnoseExplicitConv(Sema &S, SourceLocation Loc, - QualType T, - QualType ConvTy) { + virtual SemaDiagnosticBuilder diagnoseExplicitConv( + Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) { return S.Diag(Loc, diag::err_switch_explicit_conversion) << T << ConvTy; } - virtual DiagnosticBuilder noteExplicitConv(Sema &S, CXXConversionDecl *Conv, - QualType ConvTy) { + virtual SemaDiagnosticBuilder noteExplicitConv( + Sema &S, CXXConversionDecl *Conv, QualType ConvTy) { return S.Diag(Conv->getLocation(), diag::note_switch_conversion) << ConvTy->isEnumeralType() << ConvTy; } - virtual DiagnosticBuilder diagnoseAmbiguous(Sema &S, SourceLocation Loc, - QualType T) { + virtual SemaDiagnosticBuilder diagnoseAmbiguous(Sema &S, SourceLocation Loc, + QualType T) { return S.Diag(Loc, diag::err_switch_multiple_conversions) << T; } - virtual DiagnosticBuilder noteAmbiguous(Sema &S, CXXConversionDecl *Conv, - QualType ConvTy) { + virtual SemaDiagnosticBuilder noteAmbiguous( + Sema &S, CXXConversionDecl *Conv, QualType ConvTy) { return S.Diag(Conv->getLocation(), diag::note_switch_conversion) << ConvTy->isEnumeralType() << ConvTy; } - virtual DiagnosticBuilder diagnoseConversion(Sema &S, SourceLocation Loc, - QualType T, - QualType ConvTy) { - return DiagnosticBuilder::getEmpty(); + virtual SemaDiagnosticBuilder diagnoseConversion( + Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) { + llvm_unreachable("conversion functions are permitted"); } } SwitchDiagnoser(Cond); - CondResult - = ConvertToIntegralOrEnumerationType(SwitchLoc, Cond, SwitchDiagnoser, - /*AllowScopedEnumerations*/ true); + CondResult = + PerformContextualImplicitConversion(SwitchLoc, Cond, SwitchDiagnoser); if (CondResult.isInvalid()) return StmtError(); Cond = CondResult.take(); diff --git a/test/SemaCXX/conversion-delete-expr.cpp b/test/SemaCXX/conversion-delete-expr.cpp index 0f298a819f..a1ddeb2689 100644 --- a/test/SemaCXX/conversion-delete-expr.cpp +++ b/test/SemaCXX/conversion-delete-expr.cpp @@ -2,11 +2,11 @@ // Test1 struct B { - operator char *(); // expected-note {{candidate function}} + operator char *(); // expected-note {{conversion to pointer type}} }; struct D : B { - operator int *(); // expected-note {{candidate function}} + operator int *(); // expected-note {{conversion to pointer type}} }; void f (D d) @@ -30,11 +30,11 @@ void f1 (D1 d) // Test3 struct B2 { - operator const int *(); // expected-note {{candidate function}} + operator const int *(); // expected-note {{conversion to pointer type}} }; struct D2 : B2 { - operator int *(); // expected-note {{candidate function}} + operator int *(); // expected-note {{conversion to pointer type}} }; void f2 (D2 d) @@ -44,11 +44,11 @@ void f2 (D2 d) // Test4 struct B3 { - operator const int *(); // expected-note {{candidate function}} + operator const int *(); // expected-note {{conversion to pointer type}} }; struct A3 { - operator const int *(); // expected-note {{candidate function}} + operator const int *(); // expected-note {{conversion to pointer type}} }; struct D3 : A3, B3 { @@ -78,7 +78,7 @@ void f5(X1 x) { delete x; } // OK. In selecting a conversion to pointer functio // Test7 struct Base { - operator int*(); + operator int*(); }; struct Derived : Base { @@ -87,9 +87,9 @@ struct Derived : Base { }; void foo6(const Derived cd, Derived d) { - // overload resolution selects Derived::operator int*() const; - delete cd; - delete d; + // overload resolution selects Derived::operator int*() const; + delete cd; + delete d; } // Test8 @@ -104,6 +104,6 @@ struct DD : BB { void foo7 (DD d) { - // OK. In selecting a conversion to pointer function, template convesions are skipped. - delete d; + // OK. In selecting a conversion to pointer function, template convesions are skipped. + delete d; } diff --git a/test/SemaCXX/explicit.cpp b/test/SemaCXX/explicit.cpp index 5ce2cf1913..905cbdcd0c 100644 --- a/test/SemaCXX/explicit.cpp +++ b/test/SemaCXX/explicit.cpp @@ -145,14 +145,14 @@ namespace Conversion { operator int*(); }; struct NotPtr { - explicit operator int*(); + explicit operator int*(); // expected-note {{conversion}} }; Ptr p; NotPtr np; delete p; - delete np; // expected-error {{cannot delete expression of type 'NotPtr'}} + delete np; // expected-error {{converting delete expression from type 'NotPtr' to type 'int *' invokes an explicit conversion function}} } void testFunctionPointer() diff --git a/test/SemaCXX/new-delete.cpp b/test/SemaCXX/new-delete.cpp index 8b352954a3..2663374581 100644 --- a/test/SemaCXX/new-delete.cpp +++ b/test/SemaCXX/new-delete.cpp @@ -116,8 +116,8 @@ struct X1 { }; struct X2 { - operator int*(); // expected-note {{candidate function}} - operator float*(); // expected-note {{candidate function}} + operator int*(); // expected-note {{conversion}} + operator float*(); // expected-note {{conversion}} }; void test_delete_conv(X0 x0, X1 x1, X2 x2) { diff --git a/test/SemaCXX/switch.cpp b/test/SemaCXX/switch.cpp index 517faa9a69..392dcd8698 100644 --- a/test/SemaCXX/switch.cpp +++ b/test/SemaCXX/switch.cpp @@ -85,3 +85,18 @@ void local_class(int n) { }(); } } + +namespace Conversion { + struct S { + explicit operator int(); // expected-note {{conversion}} + }; + template void f(T t) { + switch (t) { // expected-error {{explicit conversion}} + case 0: + return; + default: + break; + } + } + template void f(S); // expected-note {{instantiation of}} +}