diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -54,6 +54,14 @@ There is an analogous ``zero_call_used_regs`` attribute to allow for finer control of this feature. +Bug Fixes +------------------ +- ``CXXNewExpr::getArraySize()`` previously returned a ``llvm::Optional`` + wrapping a ``nullptr`` when the ``CXXNewExpr`` did not have an array + size expression. This was fixed and ``::getArraySize()`` will now always + either return ``None`` or a ``llvm::Optional`` wrapping a valid ``Expr*``. + This fixes `Issue #53742`_. + Improvements to Clang's diagnostics ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -83,7 +91,8 @@ - Added support for parameter pack expansion in `clang::annotate`. - The ``overloadable`` attribute can now be written in all of the syntactic - locations a declaration attribute may appear. Fixes PR53805. + locations a declaration attribute may appear. + This fixes `Issue #53805`_. Windows Support --------------- diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h --- a/clang/include/clang/AST/ExprCXX.h +++ b/clang/include/clang/AST/ExprCXX.h @@ -2261,15 +2261,32 @@ bool isArray() const { return CXXNewExprBits.IsArray; } + /// This might return None even if isArray() returns true, + /// since there might not be an array size expression. + /// If the result is not-None, it will never wrap a nullptr. Optional getArraySize() { if (!isArray()) return None; - return cast_or_null(getTrailingObjects()[arraySizeOffset()]); + + if (auto *Result = + cast_or_null(getTrailingObjects()[arraySizeOffset()])) + return Result; + + return None; } + + /// This might return None even if isArray() returns true, + /// since there might not be an array size expression. + /// If the result is not-None, it will never wrap a nullptr. Optional getArraySize() const { if (!isArray()) return None; - return cast_or_null(getTrailingObjects()[arraySizeOffset()]); + + if (auto *Result = + cast_or_null(getTrailingObjects()[arraySizeOffset()])) + return Result; + + return None; } unsigned getNumPlacementArgs() const { diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -9427,7 +9427,7 @@ bool ValueInit = false; QualType AllocType = E->getAllocatedType(); - if (Optional ArraySize = E->getArraySize()) { + if (Optional ArraySize = E->getArraySize()) { const Expr *Stripped = *ArraySize; for (; auto *ICE = dyn_cast(Stripped); Stripped = ICE->getSubExpr()) diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -2132,10 +2132,10 @@ if (E->isParenTypeId()) OS << "("; std::string TypeS; - if (Optional Size = E->getArraySize()) { + if (E->isArray()) { llvm::raw_string_ostream s(TypeS); s << '['; - if (*Size) + if (Optional Size = E->getArraySize()) (*Size)->printPretty(s, Helper, Policy); s << ']'; } diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -11912,9 +11912,9 @@ // Transform the size of the array we're allocating (if any). Optional ArraySize; - if (Optional OldArraySize = E->getArraySize()) { + if (E->isArray()) { ExprResult NewArraySize; - if (*OldArraySize) { + if (Optional OldArraySize = E->getArraySize()) { NewArraySize = getDerived().TransformExpr(*OldArraySize); if (NewArraySize.isInvalid()) return ExprError(); diff --git a/clang/test/AST/issue53742.cpp b/clang/test/AST/issue53742.cpp new file mode 100644 --- /dev/null +++ b/clang/test/AST/issue53742.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -fsyntax-only %s -verify + +struct Data { + char *a; + char *b; + bool *c; +}; + +int main() { + Data in; + in.a = new char[](); // expected-error {{cannot determine allocated array size from initializer}} + in.c = new bool[100](); + in.b = new char[100](); +}