From 6bc574daab3d3571d888cc4a21df67f2e2a14792 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Wed, 30 Jun 2010 00:20:43 +0000 Subject: [PATCH] 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 --- include/clang/Basic/DiagnosticSemaKinds.td | 13 ++++++ lib/Sema/Sema.h | 3 +- lib/Sema/SemaExprCXX.cpp | 23 ++++++++-- lib/Sema/SemaOverload.cpp | 49 +++++++++++++++++++--- lib/Sema/SemaStmt.cpp | 3 +- test/SemaCXX/new-array-size-conv.cpp | 27 ++++++++++++ test/SemaCXX/new-delete.cpp | 1 + 7 files changed, 109 insertions(+), 10 deletions(-) create mode 100644 test/SemaCXX/new-array-size-conv.cpp diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 8fd2634fe8..752e4da7e7 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -2327,6 +2327,19 @@ def err_placement_new_non_placement_delete : Error< "'operator delete'">; def err_array_size_not_integral : Error< "array size expression must have integral or enumerated type, not %0">; +def err_array_size_incomplete_type : Error< + "array size expression has incomplete class type %0">; +def err_array_size_explicit_conversion : Error< + "array size expression of type %0 requires explicit conversion to type %1">; +def note_array_size_conversion : Note< + "conversion to %select{integral|enumeration}0 type %1 declared here">; +def err_array_size_ambiguous_conversion : Error< + "ambiguous conversion of array size expression of type %0 to an integral or " + "enumeration type">; +def ext_array_size_conversion : Extension< + "implicit conversion from array size expression of type %0 to " + "%select{integral|enumeration}1 type %2 is a C++0x extension">; + def err_default_init_const : Error< "default initialization of an object of const type %0" "%select{| requires a user-provided default constructor}1">; diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index c771898d96..3ed2a51e07 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -1195,7 +1195,8 @@ public: 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 86d4d42ee0..3c64584bfc 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -721,12 +721,29 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, // 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(); + 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 86724f9a92..56e800539f 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -3075,10 +3075,35 @@ bool Sema::PerformContextuallyConvertToObjCId(Expr *&From) { /// 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. +/// +/// \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, or an invalid expression. +/// \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 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, ExprArg FromE, const PartialDiagnostic &ExplicitConvDiag, const PartialDiagnostic &ExplicitConvNote, const PartialDiagnostic &AmbigDiag, - const PartialDiagnostic &AmbigNote) { + const PartialDiagnostic &AmbigNote, + const PartialDiagnostic &ConvDiag) { Expr *From = static_cast(FromE.get()); // We can't perform any more checking for type-dependent expressions. @@ -3111,7 +3137,7 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, ExprArg FromE, // 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 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, ExprArg FromE, // Apply this conversion. DeclAccessPair Found = ViableConversions[0]; CheckMemberOperatorAccess(From->getExprLoc(), From, 0, Found); + + CXXConversionDecl *Conversion + = cast(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(), Found, cast(Found->getUnderlyingDecl())); FromE = Owned(From); diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index efd74e3c25..1abcf205dd 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -435,7 +435,8 @@ Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, ExprArg Cond, 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(); diff --git a/test/SemaCXX/new-array-size-conv.cpp b/test/SemaCXX/new-array-size-conv.cpp new file mode 100644 index 0000000000..80219a9062 --- /dev/null +++ b/test/SemaCXX/new-array-size-conv.cpp @@ -0,0 +1,27 @@ +// RUN: %clang_cc1 -fsyntax-only -pedantic -verify %s + +struct ValueInt +{ + ValueInt(int v = 0) : ValueLength(v) {} + operator int () const { return ValueLength; } // expected-note 3{{conversion to integral type 'int' declared here}} +private: + int ValueLength; +}; + +enum E { e }; +struct ValueEnum { + operator E() const; // expected-note{{conversion to enumeration type 'E' declared here}} +}; + +struct ValueBoth : ValueInt, ValueEnum { }; + +struct IndirectValueInt : ValueInt { }; +struct TwoValueInts : ValueInt, IndirectValueInt { }; + +void test() { + (void)new int[ValueInt(10)]; // expected-warning{{implicit conversion from array size expression of type 'ValueInt' to integral type 'int' is a C++0x extension}} + (void)new int[ValueEnum()]; // expected-warning{{implicit conversion from array size expression of type 'ValueEnum' to enumeration type 'E' is a C++0x extension}} + (void)new int[ValueBoth()]; // expected-error{{ambiguous conversion of array size expression of type 'ValueBoth' to an integral or enumeration type}} + + (void)new int[TwoValueInts()]; // expected-error{{ambiguous conversion of array size expression of type 'TwoValueInts' to an integral or enumeration type}} +} diff --git a/test/SemaCXX/new-delete.cpp b/test/SemaCXX/new-delete.cpp index cd1da4b593..34588c2ae1 100644 --- a/test/SemaCXX/new-delete.cpp +++ b/test/SemaCXX/new-delete.cpp @@ -287,3 +287,4 @@ void test(S1* s1, S2* s2) { (void)new S2(); // expected-error {{is a private member}} } } + -- 2.40.0