зеркало из https://github.com/microsoft/clang-1.git
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:
Родитель
e2eb89a8fb
Коммит
097e0a2cb0
|
@ -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}}
|
||||||
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче