Author: ahatanak Date: Thu Jul 25 17:02:17 2019 New Revision: 367076 URL: http://llvm.org/viewvc/llvm-project?rev=367076&view=rev Log: Revert "[Sema] Diagnose default-initialization, destruction, and copying of"
This reverts commit r365985. Prior to r365985, clang used to mark C union fields that have non-trivial ObjC ownership qualifiers as unavailable if the union was declared in a system header. r365985 stopped doing so, which caused the swift compiler to crash when it tried to import a non-trivial union. I have a patch that fixes the crash (https://reviews.llvm.org/D65256), but I'm temporarily reverting the original patch until we can decide on whether it's taking the right approach. Added: cfe/trunk/test/CodeGenObjC/Inputs/strong_in_union.h Removed: cfe/trunk/test/PCH/non-trivial-c-union.m cfe/trunk/test/SemaObjC/non-trivial-c-union.m Modified: cfe/trunk/include/clang/AST/Decl.h cfe/trunk/include/clang/AST/DeclBase.h cfe/trunk/include/clang/AST/Type.h cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td cfe/trunk/include/clang/Sema/Sema.h cfe/trunk/lib/AST/Decl.cpp cfe/trunk/lib/AST/Type.cpp cfe/trunk/lib/Sema/Sema.cpp cfe/trunk/lib/Sema/SemaDecl.cpp cfe/trunk/lib/Sema/SemaExpr.cpp cfe/trunk/lib/Sema/SemaType.cpp cfe/trunk/lib/Serialization/ASTReaderDecl.cpp cfe/trunk/lib/Serialization/ASTWriterDecl.cpp cfe/trunk/test/CodeGenObjC/strong-in-c-struct.m cfe/trunk/test/SemaObjC/arc-decls.m Modified: cfe/trunk/include/clang/AST/Decl.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=367076&r1=367075&r2=367076&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/Decl.h (original) +++ cfe/trunk/include/clang/AST/Decl.h Thu Jul 25 17:02:17 2019 @@ -3746,30 +3746,6 @@ public: RecordDeclBits.NonTrivialToPrimitiveDestroy = V; } - bool hasNonTrivialToPrimitiveDefaultInitializeCUnion() const { - return RecordDeclBits.HasNonTrivialToPrimitiveDefaultInitializeCUnion; - } - - void setHasNonTrivialToPrimitiveDefaultInitializeCUnion(bool V) { - RecordDeclBits.HasNonTrivialToPrimitiveDefaultInitializeCUnion = V; - } - - bool hasNonTrivialToPrimitiveDestructCUnion() const { - return RecordDeclBits.HasNonTrivialToPrimitiveDestructCUnion; - } - - void setHasNonTrivialToPrimitiveDestructCUnion(bool V) { - RecordDeclBits.HasNonTrivialToPrimitiveDestructCUnion = V; - } - - bool hasNonTrivialToPrimitiveCopyCUnion() const { - return RecordDeclBits.HasNonTrivialToPrimitiveCopyCUnion; - } - - void setHasNonTrivialToPrimitiveCopyCUnion(bool V) { - RecordDeclBits.HasNonTrivialToPrimitiveCopyCUnion = V; - } - /// Determine whether this class can be passed in registers. In C++ mode, /// it must have at least one trivial, non-deleted copy or move constructor. /// FIXME: This should be set as part of completeDefinition. Modified: cfe/trunk/include/clang/AST/DeclBase.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclBase.h?rev=367076&r1=367075&r2=367076&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/DeclBase.h (original) +++ cfe/trunk/include/clang/AST/DeclBase.h Thu Jul 25 17:02:17 2019 @@ -1440,13 +1440,6 @@ class DeclContext { uint64_t NonTrivialToPrimitiveCopy : 1; uint64_t NonTrivialToPrimitiveDestroy : 1; - /// The following bits indicate whether this is or contains a C union that - /// is non-trivial to default-initialize, destruct, or copy. These bits - /// imply the associated basic non-triviality predicates declared above. - uint64_t HasNonTrivialToPrimitiveDefaultInitializeCUnion : 1; - uint64_t HasNonTrivialToPrimitiveDestructCUnion : 1; - uint64_t HasNonTrivialToPrimitiveCopyCUnion : 1; - /// Indicates whether this struct is destroyed in the callee. uint64_t ParamDestroyedInCallee : 1; @@ -1455,7 +1448,7 @@ class DeclContext { }; /// Number of non-inherited bits in RecordDeclBitfields. - enum { NumRecordDeclBits = 14 }; + enum { NumRecordDeclBits = 11 }; /// Stores the bits used by OMPDeclareReductionDecl. /// If modified NumOMPDeclareReductionDeclBits and the accessor Modified: cfe/trunk/include/clang/AST/Type.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=367076&r1=367075&r2=367076&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/Type.h (original) +++ cfe/trunk/include/clang/AST/Type.h Thu Jul 25 17:02:17 2019 @@ -1130,6 +1130,12 @@ public: }; /// Check if this is a non-trivial type that would cause a C struct + /// transitively containing this type to be non-trivial. This function can be + /// used to determine whether a field of this type can be declared inside a C + /// union. + bool isNonTrivialPrimitiveCType(const ASTContext &Ctx) const; + + /// Check if this is a non-trivial type that would cause a C struct /// transitively containing this type to be non-trivial to copy and return the /// kind. PrimitiveCopyKind isNonTrivialToPrimitiveCopy() const; @@ -1158,22 +1164,6 @@ public: return isDestructedTypeImpl(*this); } - /// Check if this is or contains a C union that is non-trivial to - /// default-initialize, which is a union that has a member that is non-trivial - /// to default-initialize. If this returns true, - /// isNonTrivialToPrimitiveDefaultInitialize returns PDIK_Struct. - bool hasNonTrivialToPrimitiveDefaultInitializeCUnion() const; - - /// Check if this is or contains a C union that is non-trivial to destruct, - /// which is a union that has a member that is non-trivial to destruct. If - /// this returns true, isDestructedType returns DK_nontrivial_c_struct. - bool hasNonTrivialToPrimitiveDestructCUnion() const; - - /// Check if this is or contains a C union that is non-trivial to copy, which - /// is a union that has a member that is non-trivial to copy. If this returns - /// true, isNonTrivialToPrimitiveCopy returns PCK_Struct. - bool hasNonTrivialToPrimitiveCopyCUnion() const; - /// Determine whether expressions of the given type are forbidden /// from being lvalues in C. /// @@ -1246,11 +1236,6 @@ private: const ASTContext &C); static QualType IgnoreParens(QualType T); static DestructionKind isDestructedTypeImpl(QualType type); - - /// Check if \param RD is or contains a non-trivial C union. - static bool hasNonTrivialToPrimitiveDefaultInitializeCUnion(const RecordDecl *RD); - static bool hasNonTrivialToPrimitiveDestructCUnion(const RecordDecl *RD); - static bool hasNonTrivialToPrimitiveCopyCUnion(const RecordDecl *RD); }; } // namespace clang @@ -6264,24 +6249,6 @@ inline Qualifiers::GC QualType::getObjCG return getQualifiers().getObjCGCAttr(); } -inline bool QualType::hasNonTrivialToPrimitiveDefaultInitializeCUnion() const { - if (auto *RD = getTypePtr()->getBaseElementTypeUnsafe()->getAsRecordDecl()) - return hasNonTrivialToPrimitiveDefaultInitializeCUnion(RD); - return false; -} - -inline bool QualType::hasNonTrivialToPrimitiveDestructCUnion() const { - if (auto *RD = getTypePtr()->getBaseElementTypeUnsafe()->getAsRecordDecl()) - return hasNonTrivialToPrimitiveDestructCUnion(RD); - return false; -} - -inline bool QualType::hasNonTrivialToPrimitiveCopyCUnion() const { - if (auto *RD = getTypePtr()->getBaseElementTypeUnsafe()->getAsRecordDecl()) - return hasNonTrivialToPrimitiveCopyCUnion(RD); - return false; -} - inline FunctionType::ExtInfo getFunctionExtInfo(const Type &t) { if (const auto *PT = t.getAs<PointerType>()) { if (const auto *FT = PT->getPointeeType()->getAs<FunctionType>()) Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=367076&r1=367075&r2=367076&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Jul 25 17:02:17 2019 @@ -620,23 +620,8 @@ def warn_cstruct_memaccess : Warning< InGroup<NonTrivialMemaccess>; def note_nontrivial_field : Note< "field is non-trivial to %select{copy|default-initialize}0">; -def err_non_trivial_c_union_in_invalid_context : Error< - "cannot %select{" - "use type %1 for a function/method parameter|" - "use type %1 for function/method return|" - "default-initialize an object of type %1|" - "declare an automatic variable of type %1|" - "copy-initialize an object of type %1|" - "assign to a variable of type %1|" - "construct an automatic compound literal of type %1|" - "capture a variable of type %1|" - "cannot use volatile type %1 where it causes an lvalue-to-rvalue conversion" - "}3 " - "since it %select{contains|is}2 a union that is non-trivial to " - "%select{default-initialize|destruct|copy}0">; -def note_non_trivial_c_union : Note< - "%select{%2 has subobjects that are|%3 has type %2 that is}0 " - "non-trivial to %select{default-initialize|destruct|copy}1">; +def err_nontrivial_primitive_type_in_union : Error< + "non-trivial C types are disallowed in union">; def warn_dyn_class_memaccess : Warning< "%select{destination for|source of|first operand of|second operand of}0 this " "%1 call is a pointer to %select{|class containing a }2dynamic class %3; " Modified: cfe/trunk/include/clang/Sema/Sema.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=367076&r1=367075&r2=367076&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/Sema.h (original) +++ cfe/trunk/include/clang/Sema/Sema.h Thu Jul 25 17:02:17 2019 @@ -2114,48 +2114,6 @@ public: bool SetParamDefaultArgument(ParmVarDecl *Param, Expr *DefaultArg, SourceLocation EqualLoc); - // Contexts where using non-trivial C union types can be disallowed. This is - // passed to err_non_trivial_c_union_in_invalid_context. - enum NonTrivialCUnionContext { - // Function parameter. - NTCUC_FunctionParam, - // Function return. - NTCUC_FunctionReturn, - // Default-initialized object. - NTCUC_DefaultInitializedObject, - // Variable with automatic storage duration. - NTCUC_AutoVar, - // Initializer expression that might copy from another object. - NTCUC_CopyInit, - // Assignment. - NTCUC_Assignment, - // Compound literal. - NTCUC_CompoundLiteral, - // Block capture. - NTCUC_BlockCapture, - // lvalue-to-rvalue conversion of volatile type. - NTCUC_LValueToRValueVolatile, - }; - - /// Emit diagnostics if the initializer or any of its explicit or - /// implicitly-generated subexpressions require copying or - /// default-initializing a type that is or contains a C union type that is - /// non-trivial to copy or default-initialize. - void checkNonTrivialCUnionInInitializer(const Expr *Init, SourceLocation Loc); - - // These flags are passed to checkNonTrivialCUnion. - enum NonTrivialCUnionKind { - NTCUK_Init = 0x1, - NTCUK_Destruct = 0x2, - NTCUK_Copy = 0x4, - }; - - /// Emit diagnostics if a non-trivial C union type or a struct that contains - /// a non-trivial C union is used in an invalid context. - void checkNonTrivialCUnion(QualType QT, SourceLocation Loc, - NonTrivialCUnionContext UseContext, - unsigned NonTrivialKind); - void AddInitializerToDecl(Decl *dcl, Expr *init, bool DirectInit); void ActOnUninitializedDecl(Decl *dcl); void ActOnInitializerError(Decl *Dcl); Modified: cfe/trunk/lib/AST/Decl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=367076&r1=367075&r2=367076&view=diff ============================================================================== --- cfe/trunk/lib/AST/Decl.cpp (original) +++ cfe/trunk/lib/AST/Decl.cpp Thu Jul 25 17:02:17 2019 @@ -4252,9 +4252,6 @@ RecordDecl::RecordDecl(Kind DK, TagKind setNonTrivialToPrimitiveDefaultInitialize(false); setNonTrivialToPrimitiveCopy(false); setNonTrivialToPrimitiveDestroy(false); - setHasNonTrivialToPrimitiveDefaultInitializeCUnion(false); - setHasNonTrivialToPrimitiveDestructCUnion(false); - setHasNonTrivialToPrimitiveCopyCUnion(false); setParamDestroyedInCallee(false); setArgPassingRestrictions(APK_CanPassInRegs); } Modified: cfe/trunk/lib/AST/Type.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=367076&r1=367075&r2=367076&view=diff ============================================================================== --- cfe/trunk/lib/AST/Type.cpp (original) +++ cfe/trunk/lib/AST/Type.cpp Thu Jul 25 17:02:17 2019 @@ -2276,16 +2276,60 @@ bool QualType::isNonWeakInMRRWithObjCWea getObjCLifetime() != Qualifiers::OCL_Weak; } -bool QualType::hasNonTrivialToPrimitiveDefaultInitializeCUnion(const RecordDecl *RD) { - return RD->hasNonTrivialToPrimitiveDefaultInitializeCUnion(); -} +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 QualType::hasNonTrivialToPrimitiveDestructCUnion(const RecordDecl *RD) { - return RD->hasNonTrivialToPrimitiveDestructCUnion(); -} + bool visitWithKind(QualType::PrimitiveCopyKind PCK, QualType QT) { + if (const auto *AT = this->Ctx.getAsArrayType(QT)) + return this->asDerived().visit(Ctx.getBaseElementType(AT)); + 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::hasNonTrivialToPrimitiveCopyCUnion(const RecordDecl *RD) { - return RD->hasNonTrivialToPrimitiveCopyCUnion(); +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 Modified: cfe/trunk/lib/Sema/Sema.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.cpp?rev=367076&r1=367075&r2=367076&view=diff ============================================================================== --- cfe/trunk/lib/Sema/Sema.cpp (original) +++ cfe/trunk/lib/Sema/Sema.cpp Thu Jul 25 17:02:17 2019 @@ -1658,24 +1658,12 @@ static void markEscapingByrefs(const Fun // Set the EscapingByref flag of __block variables captured by // escaping blocks. for (const BlockDecl *BD : FSI.Blocks) { + if (BD->doesNotEscape()) + continue; for (const BlockDecl::Capture &BC : BD->captures()) { VarDecl *VD = BC.getVariable(); - if (VD->hasAttr<BlocksAttr>()) { - // Nothing to do if this is a __block variable captured by a - // non-escaping block. - if (BD->doesNotEscape()) - continue; + if (VD->hasAttr<BlocksAttr>()) VD->setEscapingByref(); - } - // Check whether the captured variable is or contains an object of - // non-trivial C union type. - QualType CapType = BC.getVariable()->getType(); - if (CapType.hasNonTrivialToPrimitiveDestructCUnion() || - CapType.hasNonTrivialToPrimitiveCopyCUnion()) - S.checkNonTrivialCUnion(BC.getVariable()->getType(), - BD->getCaretLocation(), - Sema::NTCUC_BlockCapture, - Sema::NTCUK_Destruct|Sema::NTCUK_Copy); } } Modified: cfe/trunk/lib/Sema/SemaDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=367076&r1=367075&r2=367076&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDecl.cpp (original) +++ cfe/trunk/lib/Sema/SemaDecl.cpp Thu Jul 25 17:02:17 2019 @@ -22,7 +22,6 @@ #include "clang/AST/DeclTemplate.h" #include "clang/AST/EvaluatedExprVisitor.h" #include "clang/AST/ExprCXX.h" -#include "clang/AST/NonTrivialTypeVisitor.h" #include "clang/AST/StmtCXX.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/PartialDiagnostic.h" @@ -6505,11 +6504,6 @@ NamedDecl *Sema::ActOnVariableDeclarator if (D.isInvalidType()) NewVD->setInvalidDecl(); - - if (NewVD->getType().hasNonTrivialToPrimitiveDestructCUnion() && - NewVD->hasLocalStorage()) - checkNonTrivialCUnion(NewVD->getType(), NewVD->getLocation(), - NTCUC_AutoVar, NTCUK_Destruct); } else { bool Invalid = false; @@ -8932,12 +8926,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, << FunctionType::getNameForCallConv(CC); } } - - if (NewFD->getReturnType().hasNonTrivialToPrimitiveDestructCUnion() || - NewFD->getReturnType().hasNonTrivialToPrimitiveCopyCUnion()) - checkNonTrivialCUnion(NewFD->getReturnType(), - NewFD->getReturnTypeSourceRange().getBegin(), - NTCUC_FunctionReturn, NTCUK_Destruct|NTCUK_Copy); } else { // C++11 [replacement.functions]p3: // The program's definitions shall not be specified as inline. @@ -11084,264 +11072,6 @@ bool Sema::DeduceVariableDeclarationType return VDecl->isInvalidDecl(); } -void Sema::checkNonTrivialCUnionInInitializer(const Expr *Init, - SourceLocation Loc) { - if (auto *CE = dyn_cast<ConstantExpr>(Init)) - Init = CE->getSubExpr(); - - QualType InitType = Init->getType(); - assert((InitType.hasNonTrivialToPrimitiveDefaultInitializeCUnion() || - InitType.hasNonTrivialToPrimitiveCopyCUnion()) && - "shouldn't be called if type doesn't have a non-trivial C struct"); - if (auto *ILE = dyn_cast<InitListExpr>(Init)) { - for (auto I : ILE->inits()) { - if (!I->getType().hasNonTrivialToPrimitiveDefaultInitializeCUnion() && - !I->getType().hasNonTrivialToPrimitiveCopyCUnion()) - continue; - SourceLocation SL = I->getExprLoc(); - checkNonTrivialCUnionInInitializer(I, SL.isValid() ? SL : Loc); - } - return; - } - - if (isa<ImplicitValueInitExpr>(Init)) { - if (InitType.hasNonTrivialToPrimitiveDefaultInitializeCUnion()) - checkNonTrivialCUnion(InitType, Loc, NTCUC_DefaultInitializedObject, - NTCUK_Init); - } else { - // Assume all other explicit initializers involving copying some existing - // object. - // TODO: ignore any explicit initializers where we can guarantee - // copy-elision. - if (InitType.hasNonTrivialToPrimitiveCopyCUnion()) - checkNonTrivialCUnion(InitType, Loc, NTCUC_CopyInit, NTCUK_Copy); - } -} - -namespace { - -struct DiagNonTrivalCUnionDefaultInitializeVisitor - : DefaultInitializedTypeVisitor<DiagNonTrivalCUnionDefaultInitializeVisitor, - void> { - using Super = - DefaultInitializedTypeVisitor<DiagNonTrivalCUnionDefaultInitializeVisitor, - void>; - - DiagNonTrivalCUnionDefaultInitializeVisitor( - QualType OrigTy, SourceLocation OrigLoc, - Sema::NonTrivialCUnionContext UseContext, Sema &S) - : OrigTy(OrigTy), OrigLoc(OrigLoc), UseContext(UseContext), S(S) {} - - void visitWithKind(QualType::PrimitiveDefaultInitializeKind PDIK, QualType QT, - const FieldDecl *FD, bool InNonTrivialUnion) { - if (const auto *AT = S.Context.getAsArrayType(QT)) - return this->asDerived().visit(S.Context.getBaseElementType(AT), FD, - InNonTrivialUnion); - return Super::visitWithKind(PDIK, QT, FD, InNonTrivialUnion); - } - - void visitARCStrong(QualType QT, const FieldDecl *FD, - bool InNonTrivialUnion) { - if (InNonTrivialUnion) - S.Diag(FD->getLocation(), diag::note_non_trivial_c_union) - << 1 << 0 << QT << FD->getName(); - } - - void visitARCWeak(QualType QT, const FieldDecl *FD, bool InNonTrivialUnion) { - if (InNonTrivialUnion) - S.Diag(FD->getLocation(), diag::note_non_trivial_c_union) - << 1 << 0 << QT << FD->getName(); - } - - void visitStruct(QualType QT, const FieldDecl *FD, bool InNonTrivialUnion) { - const RecordDecl *RD = QT->castAs<RecordType>()->getDecl(); - if (RD->isUnion()) { - if (OrigLoc.isValid()) { - bool IsUnion = false; - if (auto *OrigRD = OrigTy->getAsRecordDecl()) - IsUnion = OrigRD->isUnion(); - S.Diag(OrigLoc, diag::err_non_trivial_c_union_in_invalid_context) - << 0 << OrigTy << IsUnion << UseContext; - // Reset OrigLoc so that this diagnostic is emitted only once. - OrigLoc = SourceLocation(); - } - InNonTrivialUnion = true; - } - - if (InNonTrivialUnion) - S.Diag(RD->getLocation(), diag::note_non_trivial_c_union) - << 0 << 0 << QT.getUnqualifiedType() << ""; - - for (const FieldDecl *FD : RD->fields()) - asDerived().visit(FD->getType(), FD, InNonTrivialUnion); - } - - void visitTrivial(QualType QT, const FieldDecl *FD, bool InNonTrivialUnion) {} - - // The non-trivial C union type or the struct/union type that contains a - // non-trivial C union. - QualType OrigTy; - SourceLocation OrigLoc; - Sema::NonTrivialCUnionContext UseContext; - Sema &S; -}; - -struct DiagNonTrivalCUnionDestructedTypeVisitor - : DestructedTypeVisitor<DiagNonTrivalCUnionDestructedTypeVisitor, void> { - using Super = - DestructedTypeVisitor<DiagNonTrivalCUnionDestructedTypeVisitor, void>; - - DiagNonTrivalCUnionDestructedTypeVisitor( - QualType OrigTy, SourceLocation OrigLoc, - Sema::NonTrivialCUnionContext UseContext, Sema &S) - : OrigTy(OrigTy), OrigLoc(OrigLoc), UseContext(UseContext), S(S) {} - - void visitWithKind(QualType::DestructionKind DK, QualType QT, - const FieldDecl *FD, bool InNonTrivialUnion) { - if (const auto *AT = S.Context.getAsArrayType(QT)) - return this->asDerived().visit(S.Context.getBaseElementType(AT), FD, - InNonTrivialUnion); - return Super::visitWithKind(DK, QT, FD, InNonTrivialUnion); - } - - void visitARCStrong(QualType QT, const FieldDecl *FD, - bool InNonTrivialUnion) { - if (InNonTrivialUnion) - S.Diag(FD->getLocation(), diag::note_non_trivial_c_union) - << 1 << 1 << QT << FD->getName(); - } - - void visitARCWeak(QualType QT, const FieldDecl *FD, bool InNonTrivialUnion) { - if (InNonTrivialUnion) - S.Diag(FD->getLocation(), diag::note_non_trivial_c_union) - << 1 << 1 << QT << FD->getName(); - } - - void visitStruct(QualType QT, const FieldDecl *FD, bool InNonTrivialUnion) { - const RecordDecl *RD = QT->castAs<RecordType>()->getDecl(); - if (RD->isUnion()) { - if (OrigLoc.isValid()) { - bool IsUnion = false; - if (auto *OrigRD = OrigTy->getAsRecordDecl()) - IsUnion = OrigRD->isUnion(); - S.Diag(OrigLoc, diag::err_non_trivial_c_union_in_invalid_context) - << 1 << OrigTy << IsUnion << UseContext; - // Reset OrigLoc so that this diagnostic is emitted only once. - OrigLoc = SourceLocation(); - } - InNonTrivialUnion = true; - } - - if (InNonTrivialUnion) - S.Diag(RD->getLocation(), diag::note_non_trivial_c_union) - << 0 << 1 << QT.getUnqualifiedType() << ""; - - for (const FieldDecl *FD : RD->fields()) - asDerived().visit(FD->getType(), FD, InNonTrivialUnion); - } - - void visitTrivial(QualType QT, const FieldDecl *FD, bool InNonTrivialUnion) {} - void visitCXXDestructor(QualType QT, const FieldDecl *FD, - bool InNonTrivialUnion) {} - - // The non-trivial C union type or the struct/union type that contains a - // non-trivial C union. - QualType OrigTy; - SourceLocation OrigLoc; - Sema::NonTrivialCUnionContext UseContext; - Sema &S; -}; - -struct DiagNonTrivalCUnionCopyVisitor - : CopiedTypeVisitor<DiagNonTrivalCUnionCopyVisitor, false, void> { - using Super = CopiedTypeVisitor<DiagNonTrivalCUnionCopyVisitor, false, void>; - - DiagNonTrivalCUnionCopyVisitor(QualType OrigTy, SourceLocation OrigLoc, - Sema::NonTrivialCUnionContext UseContext, - Sema &S) - : OrigTy(OrigTy), OrigLoc(OrigLoc), UseContext(UseContext), S(S) {} - - void visitWithKind(QualType::PrimitiveCopyKind PCK, QualType QT, - const FieldDecl *FD, bool InNonTrivialUnion) { - if (const auto *AT = S.Context.getAsArrayType(QT)) - return this->asDerived().visit(S.Context.getBaseElementType(AT), FD, - InNonTrivialUnion); - return Super::visitWithKind(PCK, QT, FD, InNonTrivialUnion); - } - - void visitARCStrong(QualType QT, const FieldDecl *FD, - bool InNonTrivialUnion) { - if (InNonTrivialUnion) - S.Diag(FD->getLocation(), diag::note_non_trivial_c_union) - << 1 << 2 << QT << FD->getName(); - } - - void visitARCWeak(QualType QT, const FieldDecl *FD, bool InNonTrivialUnion) { - if (InNonTrivialUnion) - S.Diag(FD->getLocation(), diag::note_non_trivial_c_union) - << 1 << 2 << QT << FD->getName(); - } - - void visitStruct(QualType QT, const FieldDecl *FD, bool InNonTrivialUnion) { - const RecordDecl *RD = QT->castAs<RecordType>()->getDecl(); - if (RD->isUnion()) { - if (OrigLoc.isValid()) { - bool IsUnion = false; - if (auto *OrigRD = OrigTy->getAsRecordDecl()) - IsUnion = OrigRD->isUnion(); - S.Diag(OrigLoc, diag::err_non_trivial_c_union_in_invalid_context) - << 2 << OrigTy << IsUnion << UseContext; - // Reset OrigLoc so that this diagnostic is emitted only once. - OrigLoc = SourceLocation(); - } - InNonTrivialUnion = true; - } - - if (InNonTrivialUnion) - S.Diag(RD->getLocation(), diag::note_non_trivial_c_union) - << 0 << 2 << QT.getUnqualifiedType() << ""; - - for (const FieldDecl *FD : RD->fields()) - asDerived().visit(FD->getType(), FD, InNonTrivialUnion); - } - - void preVisit(QualType::PrimitiveCopyKind PCK, QualType QT, - const FieldDecl *FD, bool InNonTrivialUnion) {} - void visitTrivial(QualType QT, const FieldDecl *FD, bool InNonTrivialUnion) {} - void visitVolatileTrivial(QualType QT, const FieldDecl *FD, - bool InNonTrivialUnion) {} - - // The non-trivial C union type or the struct/union type that contains a - // non-trivial C union. - QualType OrigTy; - SourceLocation OrigLoc; - Sema::NonTrivialCUnionContext UseContext; - Sema &S; -}; - -} // namespace - -void Sema::checkNonTrivialCUnion(QualType QT, SourceLocation Loc, - NonTrivialCUnionContext UseContext, - unsigned NonTrivialKind) { - assert((QT.hasNonTrivialToPrimitiveDefaultInitializeCUnion() || - QT.hasNonTrivialToPrimitiveDestructCUnion() || - QT.hasNonTrivialToPrimitiveCopyCUnion()) && - "shouldn't be called if type doesn't have a non-trivial C union"); - - if ((NonTrivialKind & NTCUK_Init) && - QT.hasNonTrivialToPrimitiveDefaultInitializeCUnion()) - DiagNonTrivalCUnionDefaultInitializeVisitor(QT, Loc, UseContext, *this) - .visit(QT, nullptr, false); - if ((NonTrivialKind & NTCUK_Destruct) && - QT.hasNonTrivialToPrimitiveDestructCUnion()) - DiagNonTrivalCUnionDestructedTypeVisitor(QT, Loc, UseContext, *this) - .visit(QT, nullptr, false); - if ((NonTrivialKind & NTCUK_Copy) && QT.hasNonTrivialToPrimitiveCopyCUnion()) - DiagNonTrivalCUnionCopyVisitor(QT, Loc, UseContext, *this) - .visit(QT, nullptr, false); -} - /// AddInitializerToDecl - Adds the initializer Init to the /// declaration dcl. If DirectInit is true, this is C++ direct /// initialization rather than copy initialization. @@ -11747,12 +11477,6 @@ void Sema::AddInitializerToDecl(Decl *Re CheckForConstantInitializer(Init, DclT); } - QualType InitType = Init->getType(); - if (!InitType.isNull() && - (InitType.hasNonTrivialToPrimitiveDefaultInitializeCUnion() || - InitType.hasNonTrivialToPrimitiveCopyCUnion())) - checkNonTrivialCUnionInInitializer(Init, Init->getExprLoc()); - // We will represent direct-initialization similarly to copy-initialization: // int x(1); -as-> int x = 1; // ClassType x(a,b,c); -as-> ClassType x = ClassType(a,b,c); @@ -11877,14 +11601,7 @@ void Sema::ActOnUninitializedDecl(Decl * return; } - VarDecl::DefinitionKind DefKind = Var->isThisDeclarationADefinition(); - if (!Var->isInvalidDecl() && DefKind != VarDecl::DeclarationOnly && - Var->getType().hasNonTrivialToPrimitiveDefaultInitializeCUnion()) - checkNonTrivialCUnion(Var->getType(), Var->getLocation(), - NTCUC_DefaultInitializedObject, NTCUK_Init); - - - switch (DefKind) { + switch (Var->isThisDeclarationADefinition()) { case VarDecl::Definition: if (!Var->isStaticDataMember() || !Var->getAnyInitializer()) break; @@ -12977,11 +12694,6 @@ ParmVarDecl *Sema::CheckParameter(DeclCo Context.getAdjustedParameterType(T), TSInfo, SC, nullptr); - if (New->getType().hasNonTrivialToPrimitiveDestructCUnion() || - New->getType().hasNonTrivialToPrimitiveCopyCUnion()) - checkNonTrivialCUnion(New->getType(), New->getLocation(), - NTCUC_FunctionParam, NTCUK_Destruct|NTCUK_Copy); - // Parameters can not be abstract class types. // For record types, this is done by the AbstractClassUsageDiagnoser once // the class has been completely parsed. @@ -16228,6 +15940,7 @@ void Sema::ActOnFields(Scope *S, SourceL // Verify that all the fields are okay. SmallVector<FieldDecl*, 32> RecFields; + bool ObjCFieldLifetimeErrReported = false; for (ArrayRef<Decl *>::iterator i = Fields.begin(), end = Fields.end(); i != end; ++i) { FieldDecl *FD = cast<FieldDecl>(*i); @@ -16366,12 +16079,38 @@ void Sema::ActOnFields(Scope *S, SourceL 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) << FixItHint::CreateInsertion(FD->getLocation(), "*"); QualType T = Context.getObjCObjectPointerType(FD->getType()); FD->setType(T); + } else if (getLangOpts().allowsNonTrivialObjCLifetimeQualifiers() && + Record && !ObjCFieldLifetimeErrReported && Record->isUnion() && + !getLangOpts().CPlusPlus) { + // It's an error in ARC or Weak if a field has lifetime. + // We don't want to report this in a system header, though, + // so we just make the field unavailable. + // FIXME: that's really not sufficient; we need to make the type + // itself invalid to, say, initialize or copy. + QualType T = FD->getType(); + if (T.hasNonTrivialObjCLifetime()) { + SourceLocation loc = FD->getLocation(); + if (getSourceManager().isInSystemHeader(loc)) { + if (!FD->hasAttr<UnavailableAttr>()) { + FD->addAttr(UnavailableAttr::CreateImplicit(Context, "", + UnavailableAttr::IR_ARCFieldWithOwnership, loc)); + } + } else { + Diag(FD->getLocation(), diag::err_arc_objc_object_in_tag) + << T->isBlockPointerType() << Record->getTagKind(); + } + ObjCFieldLifetimeErrReported = true; + } } else if (getLangOpts().ObjC && getLangOpts().getGC() != LangOptions::NonGC && Record && !Record->hasObjectMember()) { @@ -16391,23 +16130,14 @@ void Sema::ActOnFields(Scope *S, SourceL if (Record && !getLangOpts().CPlusPlus && !FD->hasAttr<UnavailableAttr>()) { QualType FT = FD->getType(); - if (FT.isNonTrivialToPrimitiveDefaultInitialize()) { + if (FT.isNonTrivialToPrimitiveDefaultInitialize()) Record->setNonTrivialToPrimitiveDefaultInitialize(true); - if (FT.hasNonTrivialToPrimitiveDefaultInitializeCUnion() || - Record->isUnion()) - Record->setHasNonTrivialToPrimitiveDefaultInitializeCUnion(true); - } QualType::PrimitiveCopyKind PCK = FT.isNonTrivialToPrimitiveCopy(); - if (PCK != QualType::PCK_Trivial && PCK != QualType::PCK_VolatileTrivial) { + if (PCK != QualType::PCK_Trivial && PCK != QualType::PCK_VolatileTrivial) Record->setNonTrivialToPrimitiveCopy(true); - if (FT.hasNonTrivialToPrimitiveCopyCUnion() || Record->isUnion()) - Record->setHasNonTrivialToPrimitiveCopyCUnion(true); - } if (FT.isDestructedType()) { Record->setNonTrivialToPrimitiveDestroy(true); Record->setParamDestroyedInCallee(true); - if (FT.hasNonTrivialToPrimitiveDestructCUnion() || Record->isUnion()) - Record->setHasNonTrivialToPrimitiveDestructCUnion(true); } if (const auto *RT = FT->getAs<RecordType>()) { Modified: cfe/trunk/lib/Sema/SemaExpr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=367076&r1=367075&r2=367076&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExpr.cpp (original) +++ cfe/trunk/lib/Sema/SemaExpr.cpp Thu Jul 25 17:02:17 2019 @@ -6076,7 +6076,7 @@ Sema::BuildCompoundLiteralExpr(SourceLoc ILE->setInit(i, ConstantExpr::Create(Context, Init)); } - auto *E = new (Context) CompoundLiteralExpr(LParenLoc, TInfo, literalType, + Expr *E = new (Context) CompoundLiteralExpr(LParenLoc, TInfo, literalType, VK, LiteralExpr, isFileScope); if (isFileScope) { if (!LiteralExpr->isTypeDependent() && @@ -6094,19 +6094,6 @@ Sema::BuildCompoundLiteralExpr(SourceLoc return ExprError(); } - // Compound literals that have automatic storage duration are destroyed at - // the end of the scope. Emit diagnostics if it is or contains a C union type - // that is non-trivial to destruct. - if (!isFileScope) - if (E->getType().hasNonTrivialToPrimitiveDestructCUnion()) - checkNonTrivialCUnion(E->getType(), E->getExprLoc(), - NTCUC_CompoundLiteral, NTCUK_Destruct); - - if (E->getType().hasNonTrivialToPrimitiveDefaultInitializeCUnion() || - E->getType().hasNonTrivialToPrimitiveCopyCUnion()) - checkNonTrivialCUnionInInitializer(E->getInitializer(), - E->getInitializer()->getExprLoc()); - return MaybeBindToTemporary(E); } @@ -12556,10 +12543,6 @@ ExprResult Sema::CreateBuiltinBinOp(Sour if (auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) if (VD->hasLocalStorage() && getCurScope()->isDeclScope(VD)) BE->getBlockDecl()->setCanAvoidCopyToHeap(); - - if (LHS.get()->getType().hasNonTrivialToPrimitiveCopyCUnion()) - checkNonTrivialCUnion(LHS.get()->getType(), LHS.get()->getExprLoc(), - NTCUC_Assignment, NTCUK_Copy); } RecordModifiableNonNullParam(*this, LHS.get()); break; @@ -13972,11 +13955,6 @@ ExprResult Sema::ActOnBlockStmtExpr(Sour !BD->isDependentContext()) computeNRVO(Body, BSI); - if (RetTy.hasNonTrivialToPrimitiveDestructCUnion() || - RetTy.hasNonTrivialToPrimitiveCopyCUnion()) - checkNonTrivialCUnion(RetTy, BD->getCaretLocation(), NTCUC_FunctionReturn, - NTCUK_Destruct|NTCUK_Copy); - PopDeclContext(); // Pop the block scope now but keep it alive to the end of this function. @@ -16228,15 +16206,6 @@ static ExprResult rebuildPotentialResult } ExprResult Sema::CheckLValueToRValueConversionOperand(Expr *E) { - // Check whether the operand is or contains an object of non-trivial C union - // type. - if (E->getType().isVolatileQualified() && - (E->getType().hasNonTrivialToPrimitiveDestructCUnion() || - E->getType().hasNonTrivialToPrimitiveCopyCUnion())) - checkNonTrivialCUnion(E->getType(), E->getExprLoc(), - Sema::NTCUC_LValueToRValueVolatile, - NTCUK_Destruct|NTCUK_Copy); - // C++2a [basic.def.odr]p4: // [...] an expression of non-volatile-qualified non-class type to which // the lvalue-to-rvalue conversion is applied [...] Modified: cfe/trunk/lib/Sema/SemaType.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=367076&r1=367075&r2=367076&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaType.cpp (original) +++ cfe/trunk/lib/Sema/SemaType.cpp Thu Jul 25 17:02:17 2019 @@ -2456,11 +2456,6 @@ bool Sema::CheckFunctionReturnType(QualT return true; } - if (T.hasNonTrivialToPrimitiveDestructCUnion() || - T.hasNonTrivialToPrimitiveCopyCUnion()) - checkNonTrivialCUnion(T, Loc, NTCUC_FunctionReturn, - NTCUK_Destruct|NTCUK_Copy); - return false; } Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=367076&r1=367075&r2=367076&view=diff ============================================================================== --- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original) +++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Thu Jul 25 17:02:17 2019 @@ -794,9 +794,6 @@ ASTDeclReader::VisitRecordDeclImpl(Recor RD->setNonTrivialToPrimitiveDefaultInitialize(Record.readInt()); RD->setNonTrivialToPrimitiveCopy(Record.readInt()); RD->setNonTrivialToPrimitiveDestroy(Record.readInt()); - RD->setHasNonTrivialToPrimitiveDefaultInitializeCUnion(Record.readInt()); - RD->setHasNonTrivialToPrimitiveDestructCUnion(Record.readInt()); - RD->setHasNonTrivialToPrimitiveCopyCUnion(Record.readInt()); RD->setParamDestroyedInCallee(Record.readInt()); RD->setArgPassingRestrictions((RecordDecl::ArgPassingKind)Record.readInt()); return Redecl; Modified: cfe/trunk/lib/Serialization/ASTWriterDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterDecl.cpp?rev=367076&r1=367075&r2=367076&view=diff ============================================================================== --- cfe/trunk/lib/Serialization/ASTWriterDecl.cpp (original) +++ cfe/trunk/lib/Serialization/ASTWriterDecl.cpp Thu Jul 25 17:02:17 2019 @@ -476,9 +476,6 @@ void ASTDeclWriter::VisitRecordDecl(Reco Record.push_back(D->isNonTrivialToPrimitiveDefaultInitialize()); Record.push_back(D->isNonTrivialToPrimitiveCopy()); Record.push_back(D->isNonTrivialToPrimitiveDestroy()); - Record.push_back(D->hasNonTrivialToPrimitiveDefaultInitializeCUnion()); - Record.push_back(D->hasNonTrivialToPrimitiveDestructCUnion()); - Record.push_back(D->hasNonTrivialToPrimitiveCopyCUnion()); Record.push_back(D->isParamDestroyedInCallee()); Record.push_back(D->getArgPassingRestrictions()); @@ -2002,12 +1999,6 @@ void ASTWriter::WriteDeclAbbrevs() { Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isNonTrivialToPrimitiveDestroy Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); - // hasNonTrivialToPrimitiveDefaultInitializeCUnion - Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); - // hasNonTrivialToPrimitiveDestructCUnion - Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); - // hasNonTrivialToPrimitiveCopyCUnion - Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isParamDestroyedInCallee Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // getArgPassingRestrictions Added: cfe/trunk/test/CodeGenObjC/Inputs/strong_in_union.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/Inputs/strong_in_union.h?rev=367076&view=auto ============================================================================== --- cfe/trunk/test/CodeGenObjC/Inputs/strong_in_union.h (added) +++ cfe/trunk/test/CodeGenObjC/Inputs/strong_in_union.h Thu Jul 25 17:02:17 2019 @@ -0,0 +1,10 @@ +#ifndef STRONG_IN_UNION_H +#define STRONG_IN_UNION_H +#pragma clang system_header + +typedef union { + id f0; + int *f1; +} U; + +#endif // STRONG_IN_UNION_H Modified: cfe/trunk/test/CodeGenObjC/strong-in-c-struct.m URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/strong-in-c-struct.m?rev=367076&r1=367075&r2=367076&view=diff ============================================================================== --- cfe/trunk/test/CodeGenObjC/strong-in-c-struct.m (original) +++ cfe/trunk/test/CodeGenObjC/strong-in-c-struct.m Thu Jul 25 17:02:17 2019 @@ -1,10 +1,11 @@ -// RUN: %clang_cc1 -triple arm64-apple-ios11 -fobjc-arc -fblocks -fobjc-runtime=ios-11.0 -emit-llvm -o - -DUSESTRUCT %s | FileCheck %s +// RUN: %clang_cc1 -triple arm64-apple-ios11 -fobjc-arc -fblocks -fobjc-runtime=ios-11.0 -emit-llvm -o - -DUSESTRUCT -I %S/Inputs %s | FileCheck %s -// RUN: %clang_cc1 -triple arm64-apple-ios11 -fobjc-arc -fblocks -fobjc-runtime=ios-11.0 -emit-pch -o %t %s -// RUN: %clang_cc1 -triple arm64-apple-ios11 -fobjc-arc -fblocks -fobjc-runtime=ios-11.0 -include-pch %t -emit-llvm -o - -DUSESTRUCT %s | FileCheck %s +// RUN: %clang_cc1 -triple arm64-apple-ios11 -fobjc-arc -fblocks -fobjc-runtime=ios-11.0 -emit-pch -I %S/Inputs -o %t %s +// RUN: %clang_cc1 -triple arm64-apple-ios11 -fobjc-arc -fblocks -fobjc-runtime=ios-11.0 -include-pch %t -emit-llvm -o - -DUSESTRUCT -I %S/Inputs %s | FileCheck %s #ifndef HEADER #define HEADER +#include "strong_in_union.h" typedef void (^BlockTy)(void); @@ -694,6 +695,14 @@ void test_copy_constructor_Bitfield1(Bit Bitfield1 t = *a; } +// CHECK: define void @test_strong_in_union() +// CHECK: alloca %{{.*}} +// CHECK-NEXT: ret void + +void test_strong_in_union() { + U t; +} + // CHECK: define void @test_copy_constructor_VolatileArray( // CHECK: call void @__copy_constructor_8_8_s0_AB8s4n16_tv64w32_AE( Removed: cfe/trunk/test/PCH/non-trivial-c-union.m URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/non-trivial-c-union.m?rev=367075&view=auto ============================================================================== --- cfe/trunk/test/PCH/non-trivial-c-union.m (original) +++ cfe/trunk/test/PCH/non-trivial-c-union.m (removed) @@ -1,24 +0,0 @@ -// RUN: %clang_cc1 -fblocks -fobjc-arc -fobjc-runtime-has-weak -emit-pch -o %t.pch %s -// RUN: %clang_cc1 -fblocks -fobjc-arc -fobjc-runtime-has-weak -include-pch %t.pch -verify %s - -#ifndef HEADER -#define HEADER - -typedef union { - id f0; -} U0; - -#else - -// expected-note@-6 {{'U0' has subobjects that are non-trivial to destruct}} -// expected-note@-7 {{'U0' has subobjects that are non-trivial to copy}} -// expected-note@-8 {{'U0' has subobjects that are non-trivial to default-initialize}} -// expected-note@-8 {{f0 has type '__strong id' that is non-trivial to destruct}} -// expected-note@-9 {{f0 has type '__strong id' that is non-trivial to copy}} -// expected-note@-10 {{f0 has type '__strong id' that is non-trivial to default-initialize}} - -U0 foo0(void); // expected-error {{cannot use type 'U0' for function/method return since it is a union that is non-trivial to destruct}} expected-error {{cannot use type 'U0' for function/method return since it is a union that is non-trivial to copy}} - -U0 g0; // expected-error {{cannot default-initialize an object of type 'U0' since it is a union that is non-trivial to default-initialize}} - -#endif Modified: cfe/trunk/test/SemaObjC/arc-decls.m URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/arc-decls.m?rev=367076&r1=367075&r2=367076&view=diff ============================================================================== --- cfe/trunk/test/SemaObjC/arc-decls.m (original) +++ cfe/trunk/test/SemaObjC/arc-decls.m Thu Jul 25 17:02:17 2019 @@ -8,7 +8,11 @@ struct A { }; union u { - id u; + id u; // expected-error {{ARC forbids Objective-C objects in union}} +}; + +union u_nontrivial_c { + struct A a; // expected-error {{non-trivial C types are disallowed in union}} }; // Volatile fields are fine. Removed: cfe/trunk/test/SemaObjC/non-trivial-c-union.m URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/non-trivial-c-union.m?rev=367075&view=auto ============================================================================== --- cfe/trunk/test/SemaObjC/non-trivial-c-union.m (original) +++ cfe/trunk/test/SemaObjC/non-trivial-c-union.m (removed) @@ -1,82 +0,0 @@ -// RUN: %clang_cc1 -fsyntax-only -fblocks -fobjc-arc -fobjc-runtime-has-weak -verify %s - -typedef union { // expected-note 12 {{'U0' has subobjects that are non-trivial to default-initialize}} expected-note 36 {{'U0' has subobjects that are non-trivial to destruct}} expected-note 28 {{'U0' has subobjects that are non-trivial to copy}} - id f0; // expected-note 12 {{f0 has type '__strong id' that is non-trivial to default-initialize}} expected-note 36 {{f0 has type '__strong id' that is non-trivial to destruct}} expected-note 28 {{f0 has type '__strong id' that is non-trivial to copy}} - __weak id f1; // expected-note 12 {{f1 has type '__weak id' that is non-trivial to default-initialize}} expected-note 36 {{f1 has type '__weak id' that is non-trivial to destruct}} expected-note 28 {{f1 has type '__weak id' that is non-trivial to copy}} -} U0; - -typedef struct { - U0 f0; - id f1; -} S0; - -id g0; -U0 ug0; // expected-error {{cannot default-initialize an object of type 'U0' since it is a union that is non-trivial to default-initialize}} -U0 ug1 = { .f0 = 0 }; -S0 sg0; // expected-error {{cannot default-initialize an object of type 'S0' since it contains a union that is non-trivial to default-initialize}} -S0 sg1 = { .f0 = {0}, .f1 = 0 }; -S0 sg2 = { .f1 = 0 }; // expected-error {{cannot default-initialize an object of type 'U0' since it is a union that is non-trivial to default-initialize}} - -U0 foo0(U0); // expected-error {{cannot use type 'U0' for a function/method parameter since it is a union that is non-trivial to destruct}} expected-error {{cannot use type 'U0' for a function/method parameter since it is a union that is non-trivial to copy}} expected-error {{cannot use type 'U0' for function/method return since it is a union that is non-trivial to destruct}} expected-error {{cannot use type 'U0' for function/method return since it is a union that is non-trivial to copy}} -S0 foo1(S0); // expected-error {{cannot use type 'S0' for a function/method parameter since it contains a union that is non-trivial to destruct}} expected-error {{cannot use type 'S0' for a function/method parameter since it contains a union that is non-trivial to copy}} expected-error {{cannot use type 'S0' for function/method return since it contains a union that is non-trivial to destruct}} expected-error {{cannot use type 'S0' for function/method return since it contains a union that is non-trivial to copy}} - -@interface C --(U0)m0:(U0)arg; // expected-error {{cannot use type 'U0' for a function/method parameter since it is a union that is non-trivial to destruct}} expected-error {{cannot use type 'U0' for a function/method parameter since it is a union that is non-trivial to copy}} expected-error {{cannot use type 'U0' for function/method return since it is a union that is non-trivial to destruct}} expected-error {{cannot use type 'U0' for function/method return since it is a union that is non-trivial to copy}} --(S0)m1:(S0)arg; // expected-error {{cannot use type 'S0' for a function/method parameter since it contains a union that is non-trivial to destruct}} expected-error {{cannot use type 'S0' for a function/method parameter since it contains a union that is non-trivial to copy}} expected-error {{cannot use type 'S0' for function/method return since it contains a union that is non-trivial to destruct}} expected-error {{cannot use type 'S0' for function/method return since it contains a union that is non-trivial to copy}} -@end - -void testBlockFunction(void) { - (void)^(U0 a){ return ug0; }; // expected-error {{cannot use type 'U0' for a function/method parameter since it is a union that is non-trivial to destruct}} expected-error {{cannot use type 'U0' for a function/method parameter since it is a union that is non-trivial to copy}} expected-error {{cannot use type 'U0' for function/method return since it is a union that is non-trivial to destruct}} expected-error {{cannot use type 'U0' for function/method return since it is a union that is non-trivial to copy}} - (void)^(S0 a){ return sg0; }; // expected-error {{cannot use type 'S0' for a function/method parameter since it contains a union that is non-trivial to destruct}} expected-error {{cannot use type 'S0' for a function/method parameter since it contains a union that is non-trivial to copy}} expected-error {{cannot use type 'S0' for function/method return since it contains a union that is non-trivial to destruct}} expected-error {{cannot use type 'S0' for function/method return since it contains a union that is non-trivial to copy}} -} -void testAutoVar(void) { - U0 u0; // expected-error {{cannot declare an automatic variable of type 'U0' since it is a union that is non-trivial to destruct}} expected-error {{cannot default-initialize an object of type 'U0' since it is a union that is non-trivial to default-initialize}} - U0 u1 = ug0; // expected-error {{cannot declare an automatic variable of type 'U0' since it is a union that is non-trivial to destruct}} expected-error {{cannot copy-initialize an object of type 'U0' since it is a union that is non-trivial to copy}} - U0 u2 = { g0 }; // expected-error {{cannot declare an automatic variable of type 'U0' since it is a union that is non-trivial to destruct}} - U0 u3 = { .f1 = g0 }; // expected-error {{cannot declare an automatic variable of type 'U0' since it is a union that is non-trivial to destruct}} - S0 s0; // expected-error {{cannot declare an automatic variable of type 'S0' since it contains a union that is non-trivial to destruct}} expected-error {{cannot default-initialize an object of type 'S0' since it contains a union that is non-trivial to default-initialize}} - S0 s1 = sg0; // expected-error {{declare an automatic variable of type 'S0' since it contains a union that is non-trivial to destruct}} expected-error {{cannot copy-initialize an object of type 'S0' since it contains a union that is non-trivial to copy}} - S0 s2 = { ug0 }; // expected-error {{cannot declare an automatic variable of type 'S0' since it contains a union that is non-trivial to destruct}} expected-error {{cannot copy-initialize an object of type 'U0' since it is a union that is non-trivial to copy}} - S0 s3 = { .f0 = ug0 }; // expected-error {{cannot declare an automatic variable of type 'S0' since it contains a union that is non-trivial to destruct}} expected-error {{cannot copy-initialize an object of type 'U0' since it is a union that is non-trivial to copy}} - S0 s4 = { .f1 = g0 }; // expected-error {{cannot declare an automatic variable of type 'S0' since it contains a union that is non-trivial to destruct}} expected-error {{cannot default-initialize an object of type 'U0' since it is a union that is non-trivial to default-initialize}} -} - -void testAssignment(void) { - ug0 = ug1; // expected-error {{cannot assign to a variable of type 'U0' since it is a union that is non-trivial to copy}} - sg0 = sg1; // expected-error {{cannot assign to a variable of type 'S0' since it contains a union that is non-trivial to copy}} -} - -U0 ug2 = (U0){ .f1 = 0 }; // expected-error {{cannot copy-initialize an object of type 'U0' since it is a union that is non-trivial to copy}} -S0 sg3 = (S0){ .f0 = {0}, .f1 = 0 }; // expected-error {{cannot copy-initialize an object of type 'S0' since it contains a union that is non-trivial to copy}} -S0 *sg4 = &(S0){ .f1 = 0 }; // expected-error {{cannot default-initialize an object of type 'U0' since it is a union that is non-trivial to default-initialize}} - -void testCompoundLiteral(void) { - const U0 *t0 = &(U0){ .f0 = g0 }; // expected-error {{cannot construct an automatic compound literal of type 'U0' since it is a union that is non-trivial to destruct}} - const U0 *t1 = &(U0){ .f1 = g0 }; // expected-error {{cannot construct an automatic compound literal of type 'U0' since it is a union that is non-trivial to destruct}} - const S0 *t2 = &(S0){ .f0 = ug0 }; // expected-error {{cannot construct an automatic compound literal of type 'S0' since it contains a union that is non-trivial to destruct}} expected-error {{cannot copy-initialize an object of type 'U0' since it is a union that is non-trivial to copy}} - const S0 *t3 = &(S0){ .f1 = g0 }; // expected-error {{cannot construct an automatic compound literal of type 'S0' since it contains a union that is non-trivial to destruct}} expected-error {{cannot default-initialize an object of type 'U0' since it is a union that is non-trivial to default-initialize}} -} - -typedef void (^BlockTy)(void); -void escapingFunc(BlockTy); -void noescapingFunc(__attribute__((noescape)) BlockTy); - -void testBlockCapture(void) { - U0 t0; // expected-error {{cannot declare an automatic variable of type 'U0' since it is a union that is non-trivial to destruct}} expected-error {{cannot default-initialize an object of type 'U0' since it is a union that is non-trivial to default-initialize}} - S0 t1; // expected-error {{cannot declare an automatic variable of type 'S0' since it contains a union that is non-trivial to destruct}} expected-error {{cannot default-initialize an object of type 'S0' since it contains a union that is non-trivial to default-initialize}} - __block U0 t2; // expected-error {{cannot declare an automatic variable of type 'U0' since it is a union that is non-trivial to destruct}} expected-error {{cannot default-initialize an object of type 'U0' since it is a union that is non-trivial to default-initialize}} - __block S0 t3; // expected-error {{cannot declare an automatic variable of type 'S0' since it contains a union that is non-trivial to destruct}} expected-error {{cannot default-initialize an object of type 'S0' since it contains a union that is non-trivial to default-initialize}} - - escapingFunc(^{ g0 = t0.f0; }); // expected-error {{cannot capture a variable of type 'U0' since it is a union that is non-trivial to destruct}} expected-error {{cannot capture a variable of type 'U0' since it is a union that is non-trivial to copy}} - escapingFunc(^{ g0 = t1.f0.f0; }); // expected-error {{cannot capture a variable of type 'S0' since it contains a union that is non-trivial to destruct}} expected-error {{cannot capture a variable of type 'S0' since it contains a union that is non-trivial to copy}} - escapingFunc(^{ g0 = t2.f0; }); // expected-error {{cannot capture a variable of type 'U0' since it is a union that is non-trivial to destruct}} expected-error {{cannot capture a variable of type 'U0' since it is a union that is non-trivial to copy}} - escapingFunc(^{ g0 = t3.f0.f0; }); // expected-error {{cannot capture a variable of type 'S0' since it contains a union that is non-trivial to destruct}} expected-error {{cannot capture a variable of type 'S0' since it contains a union that is non-trivial to copy}} - noescapingFunc(^{ g0 = t0.f0; }); // expected-error {{cannot capture a variable of type 'U0' since it is a union that is non-trivial to destruct}} expected-error {{cannot capture a variable of type 'U0' since it is a union that is non-trivial to copy}} - noescapingFunc(^{ g0 = t1.f0.f0; }); // expected-error {{cannot capture a variable of type 'S0' since it contains a union that is non-trivial to destruct}} expected-error {{cannot capture a variable of type 'S0' since it contains a union that is non-trivial to copy}} - noescapingFunc(^{ g0 = t2.f0; }); - noescapingFunc(^{ g0 = t3.f0.f0; }); -} - -void testVolatileLValueToRValue(volatile U0 *a) { - (void)*a; // expected-error {{cannot use volatile type 'volatile U0' where it causes an lvalue-to-rvalue conversion since it is a union that is non-trivial to destruct}} // expected-error {{cannot use volatile type 'volatile U0' where it causes an lvalue-to-rvalue conversion since it is a union that is non-trivial to copy}} -} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits