diff options
-rw-r--r-- | clang/include/clang/Basic/DiagnosticSemaKinds.td | 6 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExprCXX.cpp | 48 | ||||
-rw-r--r-- | clang/test/SemaCXX/new-delete-cxx0x.cpp | 9 | ||||
-rw-r--r-- | clang/test/SemaCXX/new-delete.cpp | 3 |
4 files changed, 49 insertions, 17 deletions
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index f0f0a054d34..8f5e2c7e6b3 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2898,6 +2898,9 @@ def err_vm_func_decl : Error< "function declaration cannot have variably modified type">; def err_array_too_large : Error< "array is too large (%0 elements)">; +def warn_array_new_too_large : Warning<"array is too large (%0 elements)">, + // FIXME PR11644: ", will throw std::bad_array_new_length at runtime" + InGroup<DiagGroup<"bad-array-new-length">>; // -Wpadded, -Wpacked def warn_padded_struct_field : Warning< @@ -2913,6 +2916,9 @@ def warn_unnecessary_packed : Warning< "packed attribute is unnecessary for %0">, InGroup<Packed>, DefaultIgnore; def err_typecheck_negative_array_size : Error<"array size is negative">; +def warn_typecheck_negative_array_new_size : Warning<"array size is negative">, + // FIXME PR11644: ", will throw std::bad_array_new_length at runtime" + InGroup<DiagGroup<"bad-array-new-length">>; def warn_typecheck_function_qualifiers : Warning< "qualifier on function type %0 has unspecified behavior">; def err_typecheck_invalid_restrict_not_pointer : Error< diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 793b70789a9..a0fb6e44d9c 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -1018,28 +1018,44 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, if (!SizeType->isIntegralOrUnscopedEnumerationType()) 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. + // C++98 [expr.new]p7: + // The expression in a direct-new-declarator shall have integral type + // with a non-negative value. + // + // Let's see if this is a constant < 0. If so, we reject it out of + // hand. Otherwise, if it's not a constant, we must have an unparenthesized + // array type. + // + // Note: such a construct has well-defined semantics in C++11: it throws + // std::bad_array_new_length. if (!ArraySize->isValueDependent()) { llvm::APSInt Value; - if (ArraySize->isIntegerConstantExpr(Value, Context, 0, false)) { + if (ArraySize->isIntegerConstantExpr(Value, Context)) { if (Value < llvm::APSInt( llvm::APInt::getNullValue(Value.getBitWidth()), - Value.isUnsigned())) - return ExprError(Diag(ArraySize->getSourceRange().getBegin(), - diag::err_typecheck_negative_array_size) - << ArraySize->getSourceRange()); - - if (!AllocType->isDependentType()) { - unsigned ActiveSizeBits - = ConstantArrayType::getNumAddressingBits(Context, AllocType, Value); - if (ActiveSizeBits > ConstantArrayType::getMaxSizeBits(Context)) { + Value.isUnsigned())) { + if (getLangOptions().CPlusPlus0x) Diag(ArraySize->getSourceRange().getBegin(), - diag::err_array_too_large) - << Value.toString(10) + diag::warn_typecheck_negative_array_new_size) << ArraySize->getSourceRange(); - return ExprError(); + else + return ExprError(Diag(ArraySize->getSourceRange().getBegin(), + diag::err_typecheck_negative_array_size) + << ArraySize->getSourceRange()); + } else if (!AllocType->isDependentType()) { + unsigned ActiveSizeBits = + ConstantArrayType::getNumAddressingBits(Context, AllocType, Value); + if (ActiveSizeBits > ConstantArrayType::getMaxSizeBits(Context)) { + if (getLangOptions().CPlusPlus0x) + Diag(ArraySize->getSourceRange().getBegin(), + diag::warn_array_new_too_large) + << Value.toString(10) + << ArraySize->getSourceRange(); + else + return ExprError(Diag(ArraySize->getSourceRange().getBegin(), + diag::err_array_too_large) + << Value.toString(10) + << ArraySize->getSourceRange()); } } } else if (TypeIdParens.isValid()) { diff --git a/clang/test/SemaCXX/new-delete-cxx0x.cpp b/clang/test/SemaCXX/new-delete-cxx0x.cpp new file mode 100644 index 00000000000..87780ad6b8d --- /dev/null +++ b/clang/test/SemaCXX/new-delete-cxx0x.cpp @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11 -triple=i686-pc-linux-gnu + +void ugly_news(int *ip) { + // These are ill-formed according to one reading of C++98, and at the least + // have undefined behavior. But they're well-formed, and defined to throw + // std::bad_array_new_length, in C++11. + (void)new int[-1]; // expected-warning {{array size is negative}} + (void)new int[2000000000]; // expected-warning {{array is too large}} +} diff --git a/clang/test/SemaCXX/new-delete.cpp b/clang/test/SemaCXX/new-delete.cpp index 748ce777009..9cc290cbd71 100644 --- a/clang/test/SemaCXX/new-delete.cpp +++ b/clang/test/SemaCXX/new-delete.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fsyntax-only -verify %s -triple=i686-pc-linux-gnu #include <stddef.h> @@ -77,6 +77,7 @@ void bad_news(int *ip) (void)new float*(ip); // expected-error {{cannot initialize a new value of type 'float *' with an lvalue of type 'int *'}} // 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)::S::new int; // expected-error {{expected unqualified-id}} (void)new (0, 0) int; // expected-error {{no matching function for call to 'operator new'}} |