From 8dd3425077ba7d49b922f37158217a6905ca4692 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Sat, 4 Feb 2012 07:07:42 +0000 Subject: [PATCH] Don't allow a value of a scoped enumeration to be used as the first bound for an array new expression. This lays some groundwork for the implicit conversion to integral or unscoped enumeration which C++11 ICEs undergo. llvm-svn: 149772 --- .../clang/Basic/DiagnosticSemaKinds.td | 3 ++- clang/include/clang/Sema/Sema.h | 3 ++- clang/lib/Sema/SemaExprCXX.cpp | 12 ++++++--- clang/lib/Sema/SemaOverload.cpp | 25 ++++++++++++++----- clang/lib/Sema/SemaStmt.cpp | 3 ++- clang/test/SemaCXX/enum-scoped.cpp | 2 +- clang/test/SemaCXX/new-delete.cpp | 4 +-- 7 files changed, 36 insertions(+), 16 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index ab724b53c46c..2138d1de98d8 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -3976,7 +3976,8 @@ def err_placement_new_non_placement_delete : Error< "'new' expression with placement arguments refers to non-placement " "'operator delete'">; def err_array_size_not_integral : Error< - "array size expression must have integral or enumerated type, not %0">; + "array size expression must have integral or %select{|unscoped }0" + "enumeration type, not %1">; def err_array_size_incomplete_type : Error< "array size expression has incomplete class type %0">; def err_array_size_explicit_conversion : Error< diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 6a9384daec93..2069dc9704de 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -1443,7 +1443,8 @@ public: const PartialDiagnostic &ExplicitConvNote, const PartialDiagnostic &AmbigDiag, const PartialDiagnostic &AmbigNote, - const PartialDiagnostic &ConvDiag); + const PartialDiagnostic &ConvDiag, + bool AllowScopedEnumerations); ExprResult PerformObjectMemberConversion(Expr *From, NestedNameSpecifier *Qualifier, diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index a0fb6e44d9c3..158e02a450e4 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -995,12 +995,15 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, QualType ResultType = Context.getPointerType(AllocType); - // C++ 5.3.4p6: "The expression in a direct-new-declarator shall have integral - // or enumeration type with a non-negative value." + // C++98 5.3.4p6: "The expression in a direct-new-declarator shall have + // integral or enumeration type with a non-negative value." + // C++11 [expr.new]p6: The expression [...] shall be of integral or unscoped + // enumeration type, or a class type for which a single non-explicit + // conversion function to integral or unscoped enumeration type exists. if (ArraySize && !ArraySize->isTypeDependent()) { ExprResult ConvertedSize = ConvertToIntegralOrEnumerationType( StartLoc, ArraySize, - PDiag(diag::err_array_size_not_integral), + PDiag(diag::err_array_size_not_integral) << getLangOptions().CPlusPlus0x, PDiag(diag::err_array_size_incomplete_type) << ArraySize->getSourceRange(), PDiag(diag::err_array_size_explicit_conversion), @@ -1009,7 +1012,8 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, PDiag(diag::note_array_size_conversion), PDiag(getLangOptions().CPlusPlus0x ? diag::warn_cxx98_compat_array_size_conversion : - diag::ext_array_size_conversion)); + diag::ext_array_size_conversion), + /*AllowScopedEnumerations*/ false); if (ConvertedSize.isInvalid()) return ExprError(); diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 98212454b849..9527c0f2982d 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -4763,6 +4763,13 @@ ExprResult Sema::PerformContextuallyConvertToObjCPointer(Expr *From) { return ExprError(); } +/// Determine whether the provided type is an integral type, or an enumeration +/// type of a permitted flavor. +static bool isIntegralOrEnumerationType(QualType T, bool AllowScopedEnum) { + return AllowScopedEnum ? T->isIntegralOrEnumerationType() + : T->isIntegralOrUnscopedEnumerationType(); +} + /// \brief Attempt to convert the given expression to an integral or /// enumeration type. /// @@ -4797,6 +4804,9 @@ ExprResult Sema::PerformContextuallyConvertToObjCPointer(Expr *From) { /// \param ConvDiag The diagnostic to be emitted if we are calling a conversion /// function, which may be an extension in this case. /// +/// \param AllowScopedEnumerations Specifies whether conversions to scoped +/// enumerations should be considered. +/// /// \returns The expression, converted to an integral or enumeration type if /// successful. ExprResult @@ -4807,7 +4817,8 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From, const PartialDiagnostic &ExplicitConvNote, const PartialDiagnostic &AmbigDiag, const PartialDiagnostic &AmbigNote, - const PartialDiagnostic &ConvDiag) { + const PartialDiagnostic &ConvDiag, + bool AllowScopedEnumerations) { // We can't perform any more checking for type-dependent expressions. if (From->isTypeDependent()) return Owned(From); @@ -4821,7 +4832,7 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From, // If the expression already has integral or enumeration type, we're golden. QualType T = From->getType(); - if (T->isIntegralOrEnumerationType()) + if (isIntegralOrEnumerationType(T, AllowScopedEnumerations)) return DefaultLvalueConversion(From); // FIXME: Check for missing '()' if T is a function type? @@ -4852,14 +4863,16 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From, I != E; ++I) { if (CXXConversionDecl *Conversion - = dyn_cast((*I)->getUnderlyingDecl())) - if (Conversion->getConversionType().getNonReferenceType() - ->isIntegralOrEnumerationType()) { + = dyn_cast((*I)->getUnderlyingDecl())) { + if (isIntegralOrEnumerationType( + Conversion->getConversionType().getNonReferenceType(), + AllowScopedEnumerations)) { if (Conversion->isExplicit()) ExplicitConversions.addDecl(I.getDecl(), I.getAccess()); else ViableConversions.addDecl(I.getDecl(), I.getAccess()); } + } } switch (ViableConversions.size()) { @@ -4947,7 +4960,7 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From, return Owned(From); } - if (!From->getType()->isIntegralOrEnumerationType()) + if (!isIntegralOrEnumerationType(From->getType(), AllowScopedEnumerations)) Diag(Loc, NotIntDiag) << From->getType() << From->getSourceRange(); diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index 6d5824a969f9..42b608e631d4 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -504,7 +504,8 @@ Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, Expr *Cond, PDiag(diag::note_switch_conversion), PDiag(diag::err_switch_multiple_conversions), PDiag(diag::note_switch_conversion), - PDiag(0)); + PDiag(0), + /*AllowScopedEnumerations*/ true); if (CondResult.isInvalid()) return StmtError(); Cond = CondResult.take(); diff --git a/clang/test/SemaCXX/enum-scoped.cpp b/clang/test/SemaCXX/enum-scoped.cpp index 791fcf153e84..8938c8229c23 100644 --- a/clang/test/SemaCXX/enum-scoped.cpp +++ b/clang/test/SemaCXX/enum-scoped.cpp @@ -34,7 +34,7 @@ int a1[Val2]; int a2[E1::Val1]; // expected-error{{size of array has non-integer type}} int* p1 = new int[Val2]; -int* p2 = new int[E1::Val1]; // FIXME Expected-error{{must have integral}} +int* p2 = new int[E1::Val1]; // expected-error{{array size expression must have integral or unscoped enumeration type, not 'E1'}} enum class E4 { e1 = -2147483648, // ok diff --git a/clang/test/SemaCXX/new-delete.cpp b/clang/test/SemaCXX/new-delete.cpp index 9cc290cbd71e..45d4f3d0ec3c 100644 --- a/clang/test/SemaCXX/new-delete.cpp +++ b/clang/test/SemaCXX/new-delete.cpp @@ -65,7 +65,7 @@ void bad_news(int *ip) (void)new; // expected-error {{expected a type}} (void)new 4; // expected-error {{expected a type}} (void)new () int; // expected-error {{expected expression}} - (void)new int[1.1]; // expected-error {{array size expression must have integral or enumerated type, not 'double'}} + (void)new int[1.1]; // expected-error {{array size expression must have integral or enumeration type, not 'double'}} (void)new int[1][i]; // expected-error {{only the first dimension}} (void)new (int[1][i]); // expected-error {{only the first dimension}} (void)new (int[i]); // expected-warning {{when type is in parentheses}} @@ -78,7 +78,7 @@ void bad_news(int *ip) // Undefined, but clang should reject it directly. (void)new int[-1]; // expected-error {{array size is negative}} (void)new int[2000000000]; // expected-error {{array is too large}} - (void)new int[*(S*)0]; // expected-error {{array size expression must have integral or enumerated type, not 'S'}} + (void)new int[*(S*)0]; // expected-error {{array size expression must have integral or enumeration type, not 'S'}} (void)::S::new int; // expected-error {{expected unqualified-id}} (void)new (0, 0) int; // expected-error {{no matching function for call to 'operator new'}} (void)new (0L) int; // expected-error {{call to 'operator new' is ambiguous}} -- GitLab