Implement C++ DR299, which allows an implicit conversion from a class
type to an integral or enumeration type in the size of an array new
expression, e.g.,
new int[ConvertibleToInt(10)];
This is a GNU and C++0x extension.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@107229 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index c771898..3ed2a51 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -1195,7 +1195,8 @@
const PartialDiagnostic &ExplicitConvDiag,
const PartialDiagnostic &ExplicitConvNote,
const PartialDiagnostic &AmbigDiag,
- const PartialDiagnostic &AmbigNote);
+ const PartialDiagnostic &AmbigNote,
+ const PartialDiagnostic &ConvDiag);
bool PerformObjectMemberConversion(Expr *&From,
NestedNameSpecifier *Qualifier,
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 86d4d42..3c64584 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -721,12 +721,29 @@
// or enumeration type with a non-negative value."
Expr *ArraySize = (Expr *)ArraySizeE.get();
if (ArraySize && !ArraySize->isTypeDependent()) {
+
QualType SizeType = ArraySize->getType();
+ OwningExprResult ConvertedSize
+ = ConvertToIntegralOrEnumerationType(StartLoc, move(ArraySizeE),
+ PDiag(diag::err_array_size_not_integral),
+ PDiag(diag::err_array_size_incomplete_type)
+ << ArraySize->getSourceRange(),
+ PDiag(diag::err_array_size_explicit_conversion),
+ PDiag(diag::note_array_size_conversion),
+ PDiag(diag::err_array_size_ambiguous_conversion),
+ PDiag(diag::note_array_size_conversion),
+ PDiag(getLangOptions().CPlusPlus0x? 0
+ : diag::ext_array_size_conversion));
+ if (ConvertedSize.isInvalid())
+ return ExprError();
+
+ ArraySize = ConvertedSize.takeAs<Expr>();
+ ArraySizeE = Owned(ArraySize);
+ SizeType = ArraySize->getType();
if (!SizeType->isIntegralOrEnumerationType())
- return ExprError(Diag(ArraySize->getSourceRange().getBegin(),
- diag::err_array_size_not_integral)
- << SizeType << ArraySize->getSourceRange());
+ return ExprError();
+
// Let's see if this is a constant < 0. If so, we reject it out of hand.
// We don't care about special rules, so we tell the machinery it's not
// evaluated - it gives us a result in more cases.
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 86724f9..56e8005 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -3075,10 +3075,35 @@
/// integral or enumeration type, if that class type only has a single
/// conversion to an integral or enumeration type.
///
-/// \param From The expression we're converting from.
+/// \param Loc The source location of the construct that requires the
+/// conversion.
///
-/// \returns The expression converted to an integral or enumeration type,
-/// if successful, or an invalid expression.
+/// \param FromE The expression we're converting from.
+///
+/// \param NotIntDiag The diagnostic to be emitted if the expression does not
+/// have integral or enumeration type.
+///
+/// \param IncompleteDiag The diagnostic to be emitted if the expression has
+/// incomplete class type.
+///
+/// \param ExplicitConvDiag The diagnostic to be emitted if we're calling an
+/// explicit conversion function (because no implicit conversion functions
+/// were available). This is a recovery mode.
+///
+/// \param ExplicitConvNote The note to be emitted with \p ExplicitConvDiag,
+/// showing which conversion was picked.
+///
+/// \param AmbigDiag The diagnostic to be emitted if there is more than one
+/// conversion function that could convert to integral or enumeration type.
+///
+/// \param AmbigNote The note to be emitted with \p AmbigDiag for each
+/// usable conversion function.
+///
+/// \param ConvDiag The diagnostic to be emitted if we are calling a conversion
+/// function, which may be an extension in this case.
+///
+/// \returns The expression, converted to an integral or enumeration type if
+/// successful.
Sema::OwningExprResult
Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, ExprArg FromE,
const PartialDiagnostic &NotIntDiag,
@@ -3086,7 +3111,8 @@
const PartialDiagnostic &ExplicitConvDiag,
const PartialDiagnostic &ExplicitConvNote,
const PartialDiagnostic &AmbigDiag,
- const PartialDiagnostic &AmbigNote) {
+ const PartialDiagnostic &AmbigNote,
+ const PartialDiagnostic &ConvDiag) {
Expr *From = static_cast<Expr *>(FromE.get());
// We can't perform any more checking for type-dependent expressions.
@@ -3111,7 +3137,7 @@
// We must have a complete class type.
if (RequireCompleteType(Loc, T, IncompleteDiag))
- return ExprError();
+ return move(FromE);
// Look for a conversion to an integral or enumeration type.
UnresolvedSet<4> ViableConversions;
@@ -3174,6 +3200,19 @@
// Apply this conversion.
DeclAccessPair Found = ViableConversions[0];
CheckMemberOperatorAccess(From->getExprLoc(), From, 0, Found);
+
+ CXXConversionDecl *Conversion
+ = cast<CXXConversionDecl>(Found->getUnderlyingDecl());
+ QualType ConvTy
+ = Conversion->getConversionType().getNonReferenceType();
+ if (ConvDiag.getDiagID()) {
+ if (isSFINAEContext())
+ return ExprError();
+
+ Diag(Loc, ConvDiag)
+ << T << ConvTy->isEnumeralType() << ConvTy << From->getSourceRange();
+ }
+
From = BuildCXXMemberCallExpr(FromE.takeAs<Expr>(), Found,
cast<CXXConversionDecl>(Found->getUnderlyingDecl()));
FromE = Owned(From);
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index efd74e3..1abcf20 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -435,7 +435,8 @@
PDiag(diag::err_switch_explicit_conversion),
PDiag(diag::note_switch_conversion),
PDiag(diag::err_switch_multiple_conversions),
- PDiag(diag::note_switch_conversion));
+ PDiag(diag::note_switch_conversion),
+ PDiag(0));
if (ConvertedCond.isInvalid())
return StmtError();