|
29 | 29 | #include "clang/AST/Type.h"
|
30 | 30 | #include "clang/Basic/IdentifierTable.h"
|
31 | 31 | #include "clang/Basic/LLVM.h"
|
32 |
| -#include "clang/Basic/LangOptions.h" |
33 | 32 | #include "clang/Basic/Module.h"
|
34 | 33 | #include "clang/Basic/ObjCRuntime.h"
|
35 | 34 | #include "clang/Basic/PartialDiagnostic.h"
|
@@ -411,6 +410,79 @@ bool Decl::isFileContextDecl() const {
|
411 | 410 | return DC && DC->isFileContext();
|
412 | 411 | }
|
413 | 412 |
|
| 413 | +bool Decl::isFlexibleArrayMemberLike( |
| 414 | + ASTContext &Ctx, const Decl *D, QualType Ty, |
| 415 | + LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel, |
| 416 | + bool IgnoreTemplateOrMacroSubstitution) { |
| 417 | + // For compatibility with existing code, we treat arrays of length 0 or |
| 418 | + // 1 as flexible array members. |
| 419 | + const auto *CAT = Ctx.getAsConstantArrayType(Ty); |
| 420 | + if (CAT) { |
| 421 | + using FAMKind = LangOptions::StrictFlexArraysLevelKind; |
| 422 | + |
| 423 | + llvm::APInt Size = CAT->getSize(); |
| 424 | + if (StrictFlexArraysLevel == FAMKind::IncompleteOnly) |
| 425 | + return false; |
| 426 | + |
| 427 | + // GCC extension, only allowed to represent a FAM. |
| 428 | + if (Size.isZero()) |
| 429 | + return true; |
| 430 | + |
| 431 | + if (StrictFlexArraysLevel == FAMKind::ZeroOrIncomplete && Size.uge(1)) |
| 432 | + return false; |
| 433 | + |
| 434 | + if (StrictFlexArraysLevel == FAMKind::OneZeroOrIncomplete && Size.uge(2)) |
| 435 | + return false; |
| 436 | + } else if (!Ctx.getAsIncompleteArrayType(Ty)) { |
| 437 | + return false; |
| 438 | + } |
| 439 | + |
| 440 | + if (const auto *OID = dyn_cast_if_present<ObjCIvarDecl>(D)) |
| 441 | + return OID->getNextIvar() == nullptr; |
| 442 | + |
| 443 | + const auto *FD = dyn_cast_if_present<FieldDecl>(D); |
| 444 | + if (!FD) |
| 445 | + return false; |
| 446 | + |
| 447 | + if (CAT) { |
| 448 | + // GCC treats an array memeber of a union as an FAM if the size is one or |
| 449 | + // zero. |
| 450 | + llvm::APInt Size = CAT->getSize(); |
| 451 | + if (FD->getParent()->isUnion() && (Size.isZero() || Size.isOne())) |
| 452 | + return true; |
| 453 | + } |
| 454 | + |
| 455 | + // Don't consider sizes resulting from macro expansions or template argument |
| 456 | + // substitution to form C89 tail-padded arrays. |
| 457 | + if (IgnoreTemplateOrMacroSubstitution) { |
| 458 | + TypeSourceInfo *TInfo = FD->getTypeSourceInfo(); |
| 459 | + while (TInfo) { |
| 460 | + TypeLoc TL = TInfo->getTypeLoc(); |
| 461 | + |
| 462 | + // Look through typedefs. |
| 463 | + if (TypedefTypeLoc TTL = TL.getAsAdjusted<TypedefTypeLoc>()) { |
| 464 | + const TypedefNameDecl *TDL = TTL.getTypedefNameDecl(); |
| 465 | + TInfo = TDL->getTypeSourceInfo(); |
| 466 | + continue; |
| 467 | + } |
| 468 | + |
| 469 | + if (auto CTL = TL.getAs<ConstantArrayTypeLoc>()) { |
| 470 | + if (const Expr *SizeExpr = |
| 471 | + dyn_cast_if_present<IntegerLiteral>(CTL.getSizeExpr()); |
| 472 | + !SizeExpr || SizeExpr->getExprLoc().isMacroID()) |
| 473 | + return false; |
| 474 | + } |
| 475 | + |
| 476 | + break; |
| 477 | + } |
| 478 | + } |
| 479 | + |
| 480 | + // Test that the field is the last in the structure. |
| 481 | + RecordDecl::field_iterator FI( |
| 482 | + DeclContext::decl_iterator(const_cast<FieldDecl *>(FD))); |
| 483 | + return ++FI == FD->getParent()->field_end(); |
| 484 | +} |
| 485 | + |
414 | 486 | TranslationUnitDecl *Decl::getTranslationUnitDecl() {
|
415 | 487 | if (auto *TUD = dyn_cast<TranslationUnitDecl>(this))
|
416 | 488 | return TUD;
|
|
0 commit comments