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
This commit is contained in:
Richard Smith 2013-05-21 19:05:48 +00:00
Родитель e2eb89a8fb
Коммит 097e0a2cb0
10 изменённых файлов: 283 добавлений и 293 удалений

Просмотреть файл

@ -4759,13 +4759,17 @@ def err_default_init_const : Error<
def err_delete_operand : Error<"cannot delete expression of type %0">; def err_delete_operand : Error<"cannot delete expression of type %0">;
def ext_delete_void_ptr_operand : ExtWarn< def ext_delete_void_ptr_operand : ExtWarn<
"cannot delete expression with pointer-to-'void' type %0">; "cannot delete expression with pointer-to-'void' type %0">;
def err_ambiguous_delete_operand : Error<"ambiguous conversion of delete " def err_ambiguous_delete_operand : Error<
"expression of type %0 to a pointer">; "ambiguous conversion of delete expression of type %0 to a pointer">;
def warn_delete_incomplete : Warning< def warn_delete_incomplete : Warning<
"deleting pointer to incomplete type %0 may cause undefined behavior">, "deleting pointer to incomplete type %0 may cause undefined behavior">,
InGroup<DiagGroup<"delete-incomplete">>; InGroup<DiagGroup<"delete-incomplete">>;
def err_delete_incomplete_class_type : Error< def err_delete_incomplete_class_type : Error<
"deleting incomplete class type %0; no conversions to pointer type">; "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< def warn_delete_array_type : Warning<
"'delete' applied to a pointer-to-array type %0 treated as delete[]">; "'delete' applied to a pointer-to-array type %0 treated as delete[]">;
def err_no_suitable_delete_member_function_found : Error< def err_no_suitable_delete_member_function_found : Error<

Просмотреть файл

@ -906,6 +906,15 @@ public:
// Dispatch to Sema to emit the diagnostic. // Dispatch to Sema to emit the diagnostic.
SemaRef.EmitCurrentDiagnostic(DiagID); SemaRef.EmitCurrentDiagnostic(DiagID);
} }
/// Teach operator<< to produce an object of the correct type.
template<typename T>
friend const SemaDiagnosticBuilder &operator<<(
const SemaDiagnosticBuilder &Diag, const T &Value) {
const DiagnosticBuilder &BaseDiag = Diag;
BaseDiag << Value;
return Diag;
}
}; };
/// \brief Emit a diagnostic. /// \brief Emit a diagnostic.
@ -1928,58 +1937,83 @@ public:
ExprResult CheckConvertedConstantExpression(Expr *From, QualType T, ExprResult CheckConvertedConstantExpression(Expr *From, QualType T,
llvm::APSInt &Value, CCEKind CCE); llvm::APSInt &Value, CCEKind CCE);
/// \brief Abstract base class used to diagnose problems that occur while /// \brief Abstract base class used to perform a contextual implicit
/// trying to convert an expression to integral or enumeration type. /// conversion from an expression to any type passing a filter.
class ICEConvertDiagnoser { class ContextualImplicitConverter {
public: public:
bool Suppress; bool Suppress;
bool SuppressConversion; bool SuppressConversion;
ICEConvertDiagnoser(bool Suppress = false, ContextualImplicitConverter(bool Suppress = false,
bool SuppressConversion = false) bool SuppressConversion = false)
: Suppress(Suppress), SuppressConversion(SuppressConversion) { } : 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 /// \brief Emits a diagnostic complaining that the expression does not have
/// integral or enumeration type. /// integral or enumeration type.
virtual DiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc, virtual SemaDiagnosticBuilder
QualType T) = 0; diagnoseNoMatch(Sema &S, SourceLocation Loc, QualType T) = 0;
/// \brief Emits a diagnostic when the expression has incomplete class type. /// \brief Emits a diagnostic when the expression has incomplete class type.
virtual DiagnosticBuilder diagnoseIncomplete(Sema &S, SourceLocation Loc, virtual SemaDiagnosticBuilder
QualType T) = 0; diagnoseIncomplete(Sema &S, SourceLocation Loc, QualType T) = 0;
/// \brief Emits a diagnostic when the only matching conversion function /// \brief Emits a diagnostic when the only matching conversion function
/// is explicit. /// is explicit.
virtual DiagnosticBuilder diagnoseExplicitConv(Sema &S, SourceLocation Loc, virtual SemaDiagnosticBuilder diagnoseExplicitConv(
QualType T, Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) = 0;
QualType ConvTy) = 0;
/// \brief Emits a note for the explicit conversion function. /// \brief Emits a note for the explicit conversion function.
virtual DiagnosticBuilder virtual SemaDiagnosticBuilder
noteExplicitConv(Sema &S, CXXConversionDecl *Conv, QualType ConvTy) = 0; noteExplicitConv(Sema &S, CXXConversionDecl *Conv, QualType ConvTy) = 0;
/// \brief Emits a diagnostic when there are multiple possible conversion /// \brief Emits a diagnostic when there are multiple possible conversion
/// functions. /// functions.
virtual DiagnosticBuilder diagnoseAmbiguous(Sema &S, SourceLocation Loc, virtual SemaDiagnosticBuilder
QualType T) = 0; diagnoseAmbiguous(Sema &S, SourceLocation Loc, QualType T) = 0;
/// \brief Emits a note for one of the candidate conversions. /// \brief Emits a note for one of the candidate conversions.
virtual DiagnosticBuilder noteAmbiguous(Sema &S, CXXConversionDecl *Conv, virtual SemaDiagnosticBuilder
QualType ConvTy) = 0; noteAmbiguous(Sema &S, CXXConversionDecl *Conv, QualType ConvTy) = 0;
/// \brief Emits a diagnostic when we picked a conversion function /// \brief Emits a diagnostic when we picked a conversion function
/// (for cases when we are not allowed to pick a conversion function). /// (for cases when we are not allowed to pick a conversion function).
virtual DiagnosticBuilder diagnoseConversion(Sema &S, SourceLocation Loc, virtual SemaDiagnosticBuilder diagnoseConversion(
QualType T, Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) = 0;
QualType ConvTy) = 0;
virtual ~ICEConvertDiagnoser() {} virtual ~ContextualImplicitConverter() {}
}; };
ExprResult class ICEConvertDiagnoser : public ContextualImplicitConverter {
ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *FromE, bool AllowScopedEnumerations;
ICEConvertDiagnoser &Diagnoser,
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 { enum ObjCSubscriptKind {
OS_Array, OS_Array,

Просмотреть файл

@ -10391,112 +10391,52 @@ Sema::VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result,
// have a single non-explicit conversion function to an integral or // have a single non-explicit conversion function to an integral or
// unscoped enumeration type // unscoped enumeration type
ExprResult Converted; ExprResult Converted;
if (!Diagnoser.Suppress) { class CXX11ConvertDiagnoser : public ICEConvertDiagnoser {
class CXX11ConvertDiagnoser : public ICEConvertDiagnoser { public:
public: CXX11ConvertDiagnoser(bool Silent)
CXX11ConvertDiagnoser() : ICEConvertDiagnoser(false, true) { } : ICEConvertDiagnoser(/*AllowScopedEnumerations*/false,
Silent, 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;
Converted = ConvertToIntegralOrEnumerationType(DiagLoc, E, virtual SemaDiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc,
ConvertDiagnoser, QualType T) {
/*AllowScopedEnumerations*/ false); return S.Diag(Loc, diag::err_ice_not_integral) << T;
} else { }
// The caller wants to silently enquire whether this is an ICE. Don't
// produce any diagnostics if it isn't. virtual SemaDiagnosticBuilder diagnoseIncomplete(
class SilentICEConvertDiagnoser : public ICEConvertDiagnoser { Sema &S, SourceLocation Loc, QualType T) {
public: return S.Diag(Loc, diag::err_ice_incomplete_type) << T;
SilentICEConvertDiagnoser() : ICEConvertDiagnoser(true, true) { } }
virtual DiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc, virtual SemaDiagnosticBuilder diagnoseExplicitConv(
QualType T) { Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) {
return DiagnosticBuilder::getEmpty(); return S.Diag(Loc, diag::err_ice_explicit_conversion) << T << ConvTy;
} }
virtual DiagnosticBuilder diagnoseIncomplete(Sema &S, virtual SemaDiagnosticBuilder noteExplicitConv(
SourceLocation Loc, Sema &S, CXXConversionDecl *Conv, QualType ConvTy) {
QualType T) { return S.Diag(Conv->getLocation(), diag::note_ice_conversion_here)
return DiagnosticBuilder::getEmpty(); << ConvTy->isEnumeralType() << ConvTy;
} }
virtual DiagnosticBuilder diagnoseExplicitConv(Sema &S, virtual SemaDiagnosticBuilder diagnoseAmbiguous(
SourceLocation Loc, Sema &S, SourceLocation Loc, QualType T) {
QualType T, return S.Diag(Loc, diag::err_ice_ambiguous_conversion) << T;
QualType ConvTy) { }
return DiagnosticBuilder::getEmpty();
} virtual SemaDiagnosticBuilder noteAmbiguous(
Sema &S, CXXConversionDecl *Conv, QualType ConvTy) {
virtual DiagnosticBuilder noteExplicitConv(Sema &S, return S.Diag(Conv->getLocation(), diag::note_ice_conversion_here)
CXXConversionDecl *Conv, << ConvTy->isEnumeralType() << ConvTy;
QualType ConvTy) { }
return DiagnosticBuilder::getEmpty();
} virtual SemaDiagnosticBuilder diagnoseConversion(
Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) {
virtual DiagnosticBuilder diagnoseAmbiguous(Sema &S, SourceLocation Loc, llvm_unreachable("conversion functions are permitted");
QualType T) { }
return DiagnosticBuilder::getEmpty(); } ConvertDiagnoser(Diagnoser.Suppress);
}
Converted = PerformContextualImplicitConversion(DiagLoc, E,
virtual DiagnosticBuilder noteAmbiguous(Sema &S, ConvertDiagnoser);
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);
}
if (Converted.isInvalid()) if (Converted.isInvalid())
return Converted; return Converted;
E = Converted.take(); E = Converted.take();

Просмотреть файл

@ -1180,54 +1180,53 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
// C++11 [expr.new]p6: The expression [...] shall be of integral or unscoped // 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 // enumeration type, or a class type for which a single non-explicit
// conversion function to integral or unscoped enumeration type exists. // 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()) { if (ArraySize && !ArraySize->isTypeDependent()) {
class SizeConvertDiagnoser : public ICEConvertDiagnoser { class SizeConvertDiagnoser : public ICEConvertDiagnoser {
Expr *ArraySize; Expr *ArraySize;
public: public:
SizeConvertDiagnoser(Expr *ArraySize) SizeConvertDiagnoser(Expr *ArraySize)
: ICEConvertDiagnoser(false, false), ArraySize(ArraySize) { } : ICEConvertDiagnoser(/*AllowScopedEnumerations*/false, false, false),
ArraySize(ArraySize) {}
virtual DiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc,
QualType T) { virtual SemaDiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc,
QualType T) {
return S.Diag(Loc, diag::err_array_size_not_integral) return S.Diag(Loc, diag::err_array_size_not_integral)
<< S.getLangOpts().CPlusPlus11 << T; << S.getLangOpts().CPlusPlus11 << T;
} }
virtual DiagnosticBuilder diagnoseIncomplete(Sema &S, SourceLocation Loc, virtual SemaDiagnosticBuilder diagnoseIncomplete(
QualType T) { Sema &S, SourceLocation Loc, QualType T) {
return S.Diag(Loc, diag::err_array_size_incomplete_type) return S.Diag(Loc, diag::err_array_size_incomplete_type)
<< T << ArraySize->getSourceRange(); << T << ArraySize->getSourceRange();
} }
virtual DiagnosticBuilder diagnoseExplicitConv(Sema &S, virtual SemaDiagnosticBuilder diagnoseExplicitConv(
SourceLocation Loc, Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) {
QualType T,
QualType ConvTy) {
return S.Diag(Loc, diag::err_array_size_explicit_conversion) << T << ConvTy; return S.Diag(Loc, diag::err_array_size_explicit_conversion) << T << ConvTy;
} }
virtual DiagnosticBuilder noteExplicitConv(Sema &S, virtual SemaDiagnosticBuilder noteExplicitConv(
CXXConversionDecl *Conv, Sema &S, CXXConversionDecl *Conv, QualType ConvTy) {
QualType ConvTy) {
return S.Diag(Conv->getLocation(), diag::note_array_size_conversion) return S.Diag(Conv->getLocation(), diag::note_array_size_conversion)
<< ConvTy->isEnumeralType() << ConvTy; << ConvTy->isEnumeralType() << ConvTy;
} }
virtual DiagnosticBuilder diagnoseAmbiguous(Sema &S, SourceLocation Loc, virtual SemaDiagnosticBuilder diagnoseAmbiguous(
QualType T) { Sema &S, SourceLocation Loc, QualType T) {
return S.Diag(Loc, diag::err_array_size_ambiguous_conversion) << T; return S.Diag(Loc, diag::err_array_size_ambiguous_conversion) << T;
} }
virtual DiagnosticBuilder noteAmbiguous(Sema &S, CXXConversionDecl *Conv, virtual SemaDiagnosticBuilder noteAmbiguous(
QualType ConvTy) { Sema &S, CXXConversionDecl *Conv, QualType ConvTy) {
return S.Diag(Conv->getLocation(), diag::note_array_size_conversion) return S.Diag(Conv->getLocation(), diag::note_array_size_conversion)
<< ConvTy->isEnumeralType() << ConvTy; << ConvTy->isEnumeralType() << ConvTy;
} }
virtual DiagnosticBuilder diagnoseConversion(Sema &S, SourceLocation Loc, virtual SemaDiagnosticBuilder diagnoseConversion(
QualType T, Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) {
QualType ConvTy) {
return S.Diag(Loc, return S.Diag(Loc,
S.getLangOpts().CPlusPlus11 S.getLangOpts().CPlusPlus11
? diag::warn_cxx98_compat_array_size_conversion ? diag::warn_cxx98_compat_array_size_conversion
@ -1237,8 +1236,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
} SizeDiagnoser(ArraySize); } SizeDiagnoser(ArraySize);
ExprResult ConvertedSize ExprResult ConvertedSize
= ConvertToIntegralOrEnumerationType(StartLoc, ArraySize, SizeDiagnoser, = PerformContextualImplicitConversion(StartLoc, ArraySize, SizeDiagnoser);
/*AllowScopedEnumerations*/ false);
if (ConvertedSize.isInvalid()) if (ConvertedSize.isInvalid())
return ExprError(); return ExprError();
@ -2054,7 +2052,8 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
bool ArrayForm, Expr *ExE) { bool ArrayForm, Expr *ExE) {
// C++ [expr.delete]p1: // C++ [expr.delete]p1:
// The operand shall have a pointer type, or a class type having a single // 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. // 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(); QualType Type = Ex.get()->getType();
if (const RecordType *Record = Type->getAs<RecordType>()) { class DeleteConverter : public ContextualImplicitConverter {
if (RequireCompleteType(StartLoc, Type, public:
diag::err_delete_incomplete_class_type)) DeleteConverter() : ContextualImplicitConverter(false, true) {}
return ExprError();
SmallVector<CXXConversionDecl*, 4> ObjectPtrConversions; bool match(QualType ConvType) {
// FIXME: If we have an operator T* and an operator void*, we must pick
CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl()); // the operator T*.
std::pair<CXXRecordDecl::conversion_iterator,
CXXRecordDecl::conversion_iterator>
Conversions = RD->getVisibleConversionFunctions();
for (CXXRecordDecl::conversion_iterator
I = Conversions.first, E = Conversions.second; I != E; ++I) {
NamedDecl *D = I.getDecl();
if (isa<UsingShadowDecl>(D))
D = cast<UsingShadowDecl>(D)->getTargetDecl();
// Skip over templated conversion functions; they aren't considered.
if (isa<FunctionTemplateDecl>(D))
continue;
CXXConversionDecl *Conv = cast<CXXConversionDecl>(D);
QualType ConvType = Conv->getConversionType().getNonReferenceType();
if (const PointerType *ConvPtrType = ConvType->getAs<PointerType>()) if (const PointerType *ConvPtrType = ConvType->getAs<PointerType>())
if (ConvPtrType->getPointeeType()->isIncompleteOrObjectType()) 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()) SemaDiagnosticBuilder diagnoseNoMatch(Sema &S, SourceLocation Loc,
return ExprError(Diag(StartLoc, diag::err_delete_operand) QualType T) {
<< Type << Ex.get()->getSourceRange()); 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<PointerType>()->getPointeeType(); QualType Pointee = Type->getAs<PointerType>()->getPointeeType();
QualType PointeeElem = Context.getBaseElementType(Pointee); QualType PointeeElem = Context.getBaseElementType(Pointee);
@ -2246,7 +2251,6 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
PDiag(diag::err_access_dtor) << PointeeElem); PDiag(diag::err_access_dtor) << PointeeElem);
} }
} }
} }
return Owned(new (Context) CXXDeleteExpr(Context.VoidTy, UseGlobal, ArrayForm, return Owned(new (Context) CXXDeleteExpr(Context.VoidTy, UseGlobal, ArrayForm,

Просмотреть файл

@ -5116,34 +5116,31 @@ ExprResult Sema::PerformContextuallyConvertToObjCPointer(Expr *From) {
/// Determine whether the provided type is an integral type, or an enumeration /// Determine whether the provided type is an integral type, or an enumeration
/// type of a permitted flavor. /// type of a permitted flavor.
static bool isIntegralOrEnumerationType(QualType T, bool AllowScopedEnum) { bool Sema::ICEConvertDiagnoser::match(QualType T) {
return AllowScopedEnum ? T->isIntegralOrEnumerationType() return AllowScopedEnumerations ? T->isIntegralOrEnumerationType()
: T->isIntegralOrUnscopedEnumerationType(); : T->isIntegralOrUnscopedEnumerationType();
} }
/// \brief Attempt to convert the given expression to an integral or /// \brief Attempt to convert the given expression to a type which is accepted
/// enumeration type. /// by the given converter.
/// ///
/// This routine will attempt to convert an expression of class type to an /// This routine will attempt to convert an expression of class type to a
/// integral or enumeration type, if that class type only has a single /// type accepted by the specified converter. In C++11 and before, the class
/// conversion to an integral or enumeration type. /// 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 /// \param Loc The source location of the construct that requires the
/// conversion. /// conversion.
/// ///
/// \param From The expression we're converting from. /// \param From The expression we're converting from.
/// ///
/// \param Diagnoser Used to output any diagnostics. /// \param Converter Used to control and diagnose the conversion process.
///
/// \param AllowScopedEnumerations Specifies whether conversions to scoped
/// enumerations should be considered.
/// ///
/// \returns The expression, converted to an integral or enumeration type if /// \returns The expression, converted to an integral or enumeration type if
/// successful. /// successful.
ExprResult ExprResult Sema::PerformContextualImplicitConversion(
Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From, SourceLocation Loc, Expr *From, ContextualImplicitConverter &Converter) {
ICEConvertDiagnoser &Diagnoser,
bool AllowScopedEnumerations) {
// We can't perform any more checking for type-dependent expressions. // We can't perform any more checking for type-dependent expressions.
if (From->isTypeDependent()) if (From->isTypeDependent())
return Owned(From); return Owned(From);
@ -5155,34 +5152,34 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From,
From = result.take(); 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(); QualType T = From->getType();
if (isIntegralOrEnumerationType(T, AllowScopedEnumerations)) if (Converter.match(T))
return DefaultLvalueConversion(From); return DefaultLvalueConversion(From);
// FIXME: Check for missing '()' if T is a function type? // 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 // We can only perform contextual implicit conversions on objects of class
// expression of integral or enumeration type. // type.
const RecordType *RecordTy = T->getAs<RecordType>(); const RecordType *RecordTy = T->getAs<RecordType>();
if (!RecordTy || !getLangOpts().CPlusPlus) { if (!RecordTy || !getLangOpts().CPlusPlus) {
if (!Diagnoser.Suppress) if (!Converter.Suppress)
Diagnoser.diagnoseNotInt(*this, Loc, T) << From->getSourceRange(); Converter.diagnoseNoMatch(*this, Loc, T) << From->getSourceRange();
return Owned(From); return Owned(From);
} }
// We must have a complete class type. // We must have a complete class type.
struct TypeDiagnoserPartialDiag : TypeDiagnoser { struct TypeDiagnoserPartialDiag : TypeDiagnoser {
ICEConvertDiagnoser &Diagnoser; ContextualImplicitConverter &Converter;
Expr *From; Expr *From;
TypeDiagnoserPartialDiag(ICEConvertDiagnoser &Diagnoser, Expr *From) TypeDiagnoserPartialDiag(ContextualImplicitConverter &Converter, Expr *From)
: TypeDiagnoser(Diagnoser.Suppress), Diagnoser(Diagnoser), From(From) {} : TypeDiagnoser(Converter.Suppress), Converter(Converter), From(From) {}
virtual void diagnose(Sema &S, SourceLocation Loc, QualType T) { 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)) if (RequireCompleteType(Loc, T, IncompleteDiagnoser))
return Owned(From); return Owned(From);
@ -5201,9 +5198,8 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From,
I = Conversions.first, E = Conversions.second; I != E; ++I) { I = Conversions.first, E = Conversions.second; I != E; ++I) {
if (CXXConversionDecl *Conversion if (CXXConversionDecl *Conversion
= dyn_cast<CXXConversionDecl>((*I)->getUnderlyingDecl())) { = dyn_cast<CXXConversionDecl>((*I)->getUnderlyingDecl())) {
if (isIntegralOrEnumerationType( if (Converter.match(
Conversion->getConversionType().getNonReferenceType(), Conversion->getConversionType().getNonReferenceType())) {
AllowScopedEnumerations)) {
if (Conversion->isExplicit()) if (Conversion->isExplicit())
ExplicitConversions.addDecl(I.getDecl(), I.getAccess()); ExplicitConversions.addDecl(I.getDecl(), I.getAccess());
else else
@ -5212,9 +5208,10 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From,
} }
} }
// FIXME: Implement the C++11 rules!
switch (ViableConversions.size()) { switch (ViableConversions.size()) {
case 0: case 0:
if (ExplicitConversions.size() == 1 && !Diagnoser.Suppress) { if (ExplicitConversions.size() == 1 && !Converter.Suppress) {
DeclAccessPair Found = ExplicitConversions[0]; DeclAccessPair Found = ExplicitConversions[0];
CXXConversionDecl *Conversion CXXConversionDecl *Conversion
= cast<CXXConversionDecl>(Found->getUnderlyingDecl()); = cast<CXXConversionDecl>(Found->getUnderlyingDecl());
@ -5226,12 +5223,12 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From,
std::string TypeStr; std::string TypeStr;
ConvTy.getAsStringInternal(TypeStr, getPrintingPolicy()); ConvTy.getAsStringInternal(TypeStr, getPrintingPolicy());
Diagnoser.diagnoseExplicitConv(*this, Loc, T, ConvTy) Converter.diagnoseExplicitConv(*this, Loc, T, ConvTy)
<< FixItHint::CreateInsertion(From->getLocStart(), << FixItHint::CreateInsertion(From->getLocStart(),
"static_cast<" + TypeStr + ">(") "static_cast<" + TypeStr + ">(")
<< FixItHint::CreateInsertion(PP.getLocForEndOfToken(From->getLocEnd()), << 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 // If we aren't in a SFINAE context, build a call to the
// explicit conversion function. // explicit conversion function.
@ -5262,11 +5259,11 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From,
= cast<CXXConversionDecl>(Found->getUnderlyingDecl()); = cast<CXXConversionDecl>(Found->getUnderlyingDecl());
QualType ConvTy QualType ConvTy
= Conversion->getConversionType().getNonReferenceType(); = Conversion->getConversionType().getNonReferenceType();
if (!Diagnoser.SuppressConversion) { if (!Converter.SuppressConversion) {
if (isSFINAEContext()) if (isSFINAEContext())
return ExprError(); return ExprError();
Diagnoser.diagnoseConversion(*this, Loc, T, ConvTy) Converter.diagnoseConversion(*this, Loc, T, ConvTy)
<< From->getSourceRange(); << From->getSourceRange();
} }
@ -5283,24 +5280,22 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From,
} }
default: default:
if (Diagnoser.Suppress) if (Converter.Suppress)
return ExprError(); 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) { for (unsigned I = 0, N = ViableConversions.size(); I != N; ++I) {
CXXConversionDecl *Conv CXXConversionDecl *Conv
= cast<CXXConversionDecl>(ViableConversions[I]->getUnderlyingDecl()); = cast<CXXConversionDecl>(ViableConversions[I]->getUnderlyingDecl());
QualType ConvTy = Conv->getConversionType().getNonReferenceType(); QualType ConvTy = Conv->getConversionType().getNonReferenceType();
Diagnoser.noteAmbiguous(*this, Conv, ConvTy); Converter.noteAmbiguous(*this, Conv, ConvTy);
} }
return Owned(From); return Owned(From);
} }
if (!isIntegralOrEnumerationType(From->getType(), AllowScopedEnumerations) && if (!Converter.match(From->getType()) && !Converter.Suppress)
!Diagnoser.Suppress) { Converter.diagnoseNoMatch(*this, Loc, From->getType())
Diagnoser.diagnoseNotInt(*this, Loc, From->getType())
<< From->getSourceRange(); << From->getSourceRange();
}
return DefaultLvalueConversion(From); return DefaultLvalueConversion(From);
} }

Просмотреть файл

@ -592,52 +592,50 @@ Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, Expr *Cond,
public: public:
SwitchConvertDiagnoser(Expr *Cond) SwitchConvertDiagnoser(Expr *Cond)
: ICEConvertDiagnoser(false, true), Cond(Cond) { } : ICEConvertDiagnoser(/*AllowScopedEnumerations*/true, false, true),
Cond(Cond) {}
virtual DiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc, virtual SemaDiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc,
QualType T) { QualType T) {
return S.Diag(Loc, diag::err_typecheck_statement_requires_integer) << T; return S.Diag(Loc, diag::err_typecheck_statement_requires_integer) << T;
} }
virtual DiagnosticBuilder diagnoseIncomplete(Sema &S, SourceLocation Loc, virtual SemaDiagnosticBuilder diagnoseIncomplete(
QualType T) { Sema &S, SourceLocation Loc, QualType T) {
return S.Diag(Loc, diag::err_switch_incomplete_class_type) return S.Diag(Loc, diag::err_switch_incomplete_class_type)
<< T << Cond->getSourceRange(); << T << Cond->getSourceRange();
} }
virtual DiagnosticBuilder diagnoseExplicitConv(Sema &S, SourceLocation Loc, virtual SemaDiagnosticBuilder diagnoseExplicitConv(
QualType T, Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) {
QualType ConvTy) {
return S.Diag(Loc, diag::err_switch_explicit_conversion) << T << ConvTy; return S.Diag(Loc, diag::err_switch_explicit_conversion) << T << ConvTy;
} }
virtual DiagnosticBuilder noteExplicitConv(Sema &S, CXXConversionDecl *Conv, virtual SemaDiagnosticBuilder noteExplicitConv(
QualType ConvTy) { Sema &S, CXXConversionDecl *Conv, QualType ConvTy) {
return S.Diag(Conv->getLocation(), diag::note_switch_conversion) return S.Diag(Conv->getLocation(), diag::note_switch_conversion)
<< ConvTy->isEnumeralType() << ConvTy; << ConvTy->isEnumeralType() << ConvTy;
} }
virtual DiagnosticBuilder diagnoseAmbiguous(Sema &S, SourceLocation Loc, virtual SemaDiagnosticBuilder diagnoseAmbiguous(Sema &S, SourceLocation Loc,
QualType T) { QualType T) {
return S.Diag(Loc, diag::err_switch_multiple_conversions) << T; return S.Diag(Loc, diag::err_switch_multiple_conversions) << T;
} }
virtual DiagnosticBuilder noteAmbiguous(Sema &S, CXXConversionDecl *Conv, virtual SemaDiagnosticBuilder noteAmbiguous(
QualType ConvTy) { Sema &S, CXXConversionDecl *Conv, QualType ConvTy) {
return S.Diag(Conv->getLocation(), diag::note_switch_conversion) return S.Diag(Conv->getLocation(), diag::note_switch_conversion)
<< ConvTy->isEnumeralType() << ConvTy; << ConvTy->isEnumeralType() << ConvTy;
} }
virtual DiagnosticBuilder diagnoseConversion(Sema &S, SourceLocation Loc, virtual SemaDiagnosticBuilder diagnoseConversion(
QualType T, Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) {
QualType ConvTy) { llvm_unreachable("conversion functions are permitted");
return DiagnosticBuilder::getEmpty();
} }
} SwitchDiagnoser(Cond); } SwitchDiagnoser(Cond);
CondResult CondResult =
= ConvertToIntegralOrEnumerationType(SwitchLoc, Cond, SwitchDiagnoser, PerformContextualImplicitConversion(SwitchLoc, Cond, SwitchDiagnoser);
/*AllowScopedEnumerations*/ true);
if (CondResult.isInvalid()) return StmtError(); if (CondResult.isInvalid()) return StmtError();
Cond = CondResult.take(); Cond = CondResult.take();

Просмотреть файл

@ -2,11 +2,11 @@
// Test1 // Test1
struct B { struct B {
operator char *(); // expected-note {{candidate function}} operator char *(); // expected-note {{conversion to pointer type}}
}; };
struct D : B { struct D : B {
operator int *(); // expected-note {{candidate function}} operator int *(); // expected-note {{conversion to pointer type}}
}; };
void f (D d) void f (D d)
@ -30,11 +30,11 @@ void f1 (D1 d)
// Test3 // Test3
struct B2 { struct B2 {
operator const int *(); // expected-note {{candidate function}} operator const int *(); // expected-note {{conversion to pointer type}}
}; };
struct D2 : B2 { struct D2 : B2 {
operator int *(); // expected-note {{candidate function}} operator int *(); // expected-note {{conversion to pointer type}}
}; };
void f2 (D2 d) void f2 (D2 d)
@ -44,11 +44,11 @@ void f2 (D2 d)
// Test4 // Test4
struct B3 { struct B3 {
operator const int *(); // expected-note {{candidate function}} operator const int *(); // expected-note {{conversion to pointer type}}
}; };
struct A3 { struct A3 {
operator const int *(); // expected-note {{candidate function}} operator const int *(); // expected-note {{conversion to pointer type}}
}; };
struct D3 : A3, B3 { struct D3 : A3, B3 {
@ -78,7 +78,7 @@ void f5(X1 x) { delete x; } // OK. In selecting a conversion to pointer functio
// Test7 // Test7
struct Base { struct Base {
operator int*(); operator int*();
}; };
struct Derived : Base { struct Derived : Base {
@ -87,9 +87,9 @@ struct Derived : Base {
}; };
void foo6(const Derived cd, Derived d) { void foo6(const Derived cd, Derived d) {
// overload resolution selects Derived::operator int*() const; // overload resolution selects Derived::operator int*() const;
delete cd; delete cd;
delete d; delete d;
} }
// Test8 // Test8
@ -104,6 +104,6 @@ struct DD : BB {
void foo7 (DD d) void foo7 (DD d)
{ {
// OK. In selecting a conversion to pointer function, template convesions are skipped. // OK. In selecting a conversion to pointer function, template convesions are skipped.
delete d; delete d;
} }

Просмотреть файл

@ -145,14 +145,14 @@ namespace Conversion {
operator int*(); operator int*();
}; };
struct NotPtr { struct NotPtr {
explicit operator int*(); explicit operator int*(); // expected-note {{conversion}}
}; };
Ptr p; Ptr p;
NotPtr np; NotPtr np;
delete p; 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() void testFunctionPointer()

Просмотреть файл

@ -116,8 +116,8 @@ struct X1 {
}; };
struct X2 { struct X2 {
operator int*(); // expected-note {{candidate function}} operator int*(); // expected-note {{conversion}}
operator float*(); // expected-note {{candidate function}} operator float*(); // expected-note {{conversion}}
}; };
void test_delete_conv(X0 x0, X1 x1, X2 x2) { void test_delete_conv(X0 x0, X1 x1, X2 x2) {

Просмотреть файл

@ -85,3 +85,18 @@ void local_class(int n) {
}(); }();
} }
} }
namespace Conversion {
struct S {
explicit operator int(); // expected-note {{conversion}}
};
template<typename T> void f(T t) {
switch (t) { // expected-error {{explicit conversion}}
case 0:
return;
default:
break;
}
}
template void f(S); // expected-note {{instantiation of}}
}