diff options
author | Akira Hatanaka <ahatanaka@apple.com> | 2019-02-07 20:21:46 +0000 |
---|---|---|
committer | Akira Hatanaka <ahatanaka@apple.com> | 2019-02-07 20:21:46 +0000 |
commit | 5fbdccd834874aad04e21b0253084a27013a3f81 (patch) | |
tree | 4710b8a956fff71b5c1b2acd718ce52187297103 /clang/lib | |
parent | fe3ac70b18ea2b614545734542944acf2f97bfcf (diff) | |
download | bcm5719-llvm-5fbdccd834874aad04e21b0253084a27013a3f81.tar.gz bcm5719-llvm-5fbdccd834874aad04e21b0253084a27013a3f81.zip |
[Sema][ObjC] Disallow non-trivial C struct fields in unions.
This patch fixes a bug where clang doesn’t reject union fields of
non-trivial C struct types. For example:
```
// This struct is non-trivial under ARC.
struct S0 {
id x;
};
union U0 {
struct S0 s0; // clang should reject this.
struct S0 s1; // clang should reject this.
};
void test(union U0 a) {
// Previously, both 'a.s0.x' and 'a.s1.x' were released in this
// function.
}
```
rdar://problem/46677858
Differential Revision: https://reviews.llvm.org/D55659
llvm-svn: 353459
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/AST/Type.cpp | 57 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 4 |
2 files changed, 61 insertions, 0 deletions
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 452ff6201a2..02943ccef90 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -22,6 +22,7 @@ #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/NonTrivialTypeVisitor.h" #include "clang/AST/PrettyPrinter.h" #include "clang/AST/TemplateBase.h" #include "clang/AST/TemplateName.h" @@ -2244,6 +2245,62 @@ bool QualType::isNonWeakInMRRWithObjCWeak(const ASTContext &Context) const { getObjCLifetime() != Qualifiers::OCL_Weak; } +namespace { +// Helper class that determines whether this is a type that is non-trivial to +// primitive copy or move, or is a struct type that has a field of such type. +template <bool IsMove> +struct IsNonTrivialCopyMoveVisitor + : CopiedTypeVisitor<IsNonTrivialCopyMoveVisitor<IsMove>, IsMove, bool> { + using Super = + CopiedTypeVisitor<IsNonTrivialCopyMoveVisitor<IsMove>, IsMove, bool>; + IsNonTrivialCopyMoveVisitor(const ASTContext &C) : Ctx(C) {} + void preVisit(QualType::PrimitiveCopyKind PCK, QualType QT) {} + + bool visitWithKind(QualType::PrimitiveCopyKind PCK, QualType QT) { + if (const auto *AT = this->Ctx.getAsArrayType(QT)) + return this->asDerived().visit(QualType(AT, 0)); + return Super::visitWithKind(PCK, QT); + } + + bool visitARCStrong(QualType QT) { return true; } + bool visitARCWeak(QualType QT) { return true; } + bool visitTrivial(QualType QT) { return false; } + // Volatile fields are considered trivial. + bool visitVolatileTrivial(QualType QT) { return false; } + + bool visitStruct(QualType QT) { + const RecordDecl *RD = QT->castAs<RecordType>()->getDecl(); + // We don't want to apply the C restriction in C++ because C++ + // (1) can apply the restriction at a finer grain by banning copying or + // destroying the union, and + // (2) allows users to override these restrictions by declaring explicit + // constructors/etc, which we're not proposing to add to C. + if (isa<CXXRecordDecl>(RD)) + return false; + for (const FieldDecl *FD : RD->fields()) + if (this->asDerived().visit(FD->getType())) + return true; + return false; + } + + const ASTContext &Ctx; +}; + +} // namespace + +bool QualType::isNonTrivialPrimitiveCType(const ASTContext &Ctx) const { + if (isNonTrivialToPrimitiveDefaultInitialize()) + return true; + DestructionKind DK = isDestructedType(); + if (DK != DK_none && DK != DK_cxx_destructor) + return true; + if (IsNonTrivialCopyMoveVisitor<false>(Ctx).visit(*this)) + return true; + if (IsNonTrivialCopyMoveVisitor<true>(Ctx).visit(*this)) + return true; + return false; +} + QualType::PrimitiveDefaultInitializeKind QualType::isNonTrivialToPrimitiveDefaultInitialize() const { if (const auto *RT = diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index c8a69c4d537..a9e6eb12c0d 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -15916,6 +15916,10 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, Record->setHasObjectMember(true); if (Record && FDTTy->getDecl()->hasVolatileMember()) Record->setHasVolatileMember(true); + if (Record && Record->isUnion() && + FD->getType().isNonTrivialPrimitiveCType(Context)) + Diag(FD->getLocation(), + diag::err_nontrivial_primitive_type_in_union); } else if (FDTy->isObjCObjectType()) { /// A field cannot be an Objective-c object Diag(FD->getLocation(), diag::err_statically_allocated_object) |