summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/AST/ExprConstant.cpp17
1 files changed, 12 insertions, 5 deletions
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 107913ed61b..15b554bf27a 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -6826,14 +6826,21 @@ static bool tryEvaluateBuiltinObjectSize(const Expr *E, unsigned Type,
// struct Foo *F = (struct Foo *)malloc(sizeof(struct Foo) + strlen(Bar));
// strcpy(&F->c[0], Bar);
//
- // So, if we see that we're examining a 1-length (or 0-length) array at the
- // end of a struct with an unknown base, we give up instead of breaking code
- // that behaves this way. Note that we only do this when Type=1, because
- // Type=3 is a lower bound, so answering conservatively is fine.
+ // So, if we see that we're examining an array at the end of a struct with an
+ // unknown base, we give up instead of breaking code that behaves this way.
+ // Note that we only do this when Type=1, because Type=3 is a lower bound, so
+ // answering conservatively is fine.
+ //
+ // We used to be a bit more aggressive here; we'd only be conservative if the
+ // array at the end was flexible, or if it had 0 or 1 elements. This broke
+ // some common standard library extensions (PR30346), but was otherwise
+ // seemingly fine. It may be useful to reintroduce this behavior with some
+ // sort of whitelist. OTOH, it seems that GCC is always conservative with the
+ // last element in structs (if it's an array), so our current behavior is more
+ // compatible than a whitelisting approach would be.
if (End.InvalidBase && SubobjectOnly && Type == 1 &&
End.Designator.Entries.size() == End.Designator.MostDerivedPathLength &&
End.Designator.MostDerivedIsArrayElement &&
- End.Designator.MostDerivedArraySize < 2 &&
isDesignatorAtObjectEnd(Info.Ctx, End))
return false;
OpenPOWER on IntegriCloud