diff options
Diffstat (limited to 'lib/Sema/SemaDecl.cpp')
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 83 |
1 files changed, 77 insertions, 6 deletions
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index fd172def2d..59bfa49066 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -13233,6 +13233,55 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, if (TUK == TUK_Friend || TUK == TUK_Reference) Redecl = NotForRedeclaration; + /// Create a new tag decl in C/ObjC. Since the ODR-like semantics for ObjC/C + /// implemented asks for structural equivalence checking, the returned decl + /// here is passed back to the parser, allowing the tag body to be parsed. + auto createTagFromNewDecl = [&]() -> TagDecl * { + assert(!getLangOpts().CPlusPlus && "not meant for C++ usage"); + // If there is an identifier, use the location of the identifier as the + // location of the decl, otherwise use the location of the struct/union + // keyword. + SourceLocation Loc = NameLoc.isValid() ? NameLoc : KWLoc; + TagDecl *New = nullptr; + + if (Kind == TTK_Enum) { + New = EnumDecl::Create(Context, SearchDC, KWLoc, Loc, Name, nullptr, + ScopedEnum, ScopedEnumUsesClassTag, + !EnumUnderlying.isNull()); + // If this is an undefined enum, bail. + if (TUK != TUK_Definition && !Invalid) + return nullptr; + if (EnumUnderlying) { + EnumDecl *ED = cast<EnumDecl>(New); + if (TypeSourceInfo *TI = EnumUnderlying.dyn_cast<TypeSourceInfo *>()) + ED->setIntegerTypeSourceInfo(TI); + else + ED->setIntegerType(QualType(EnumUnderlying.get<const Type *>(), 0)); + ED->setPromotionType(ED->getIntegerType()); + } + } else { // struct/union + New = RecordDecl::Create(Context, Kind, SearchDC, KWLoc, Loc, Name, + nullptr); + } + + if (RecordDecl *RD = dyn_cast<RecordDecl>(New)) { + // Add alignment attributes if necessary; these attributes are checked + // when the ASTContext lays out the structure. + // + // It is important for implementing the correct semantics that this + // happen here (in ActOnTag). The #pragma pack stack is + // maintained as a result of parser callbacks which can occur at + // many points during the parsing of a struct declaration (because + // the #pragma tokens are effectively skipped over during the + // parsing of the struct). + if (TUK == TUK_Definition) { + AddAlignmentAttributesForRecord(RD); + AddMsStructLayoutForRecord(RD); + } + } + return New; + }; + LookupResult Previous(*this, Name, NameLoc, LookupTagName, Redecl); if (Name && SS.isNotEmpty()) { // We have a nested-name tag ('struct foo::bar'). @@ -13638,16 +13687,28 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, TSK_ExplicitSpecialization; } + // Note that clang allows ODR-like semantics for ObjC/C, i.e., do + // not keep more that one definition around (merge them). However, + // ensure the decl passes the structural compatibility check in + // C11 6.2.7/1 (or 6.1.2.6/1 in C89). NamedDecl *Hidden = nullptr; - if (SkipBody && getLangOpts().CPlusPlus && - !hasVisibleDefinition(Def, &Hidden)) { + if (SkipBody && !hasVisibleDefinition(Def, &Hidden)) { // There is a definition of this tag, but it is not visible. We // explicitly make use of C++'s one definition rule here, and // assume that this definition is identical to the hidden one // we already have. Make the existing definition visible and // use it in place of this one. - SkipBody->ShouldSkip = true; - makeMergedDefinitionVisible(Hidden); + if (!getLangOpts().CPlusPlus) { + // Postpone making the old definition visible until after we + // complete parsing the new one and do the structural + // comparison. + SkipBody->CheckSameAsPrevious = true; + SkipBody->New = createTagFromNewDecl(); + SkipBody->Previous = Hidden; + } else { + SkipBody->ShouldSkip = true; + makeMergedDefinitionVisible(Hidden); + } return Def; } else if (!IsExplicitSpecializationAfterInstantiation) { // A redeclaration in function prototype scope in C isn't @@ -13875,7 +13936,7 @@ CreateNewDecl: // the ASTContext lays out the structure. // // It is important for implementing the correct semantics that this - // happen here (in act on tag decl). The #pragma pack stack is + // happen here (in ActOnTag). The #pragma pack stack is // maintained as a result of parser callbacks which can occur at // many points during the parsing of a struct declaration (because // the #pragma tokens are effectively skipped over during the @@ -14011,6 +14072,16 @@ void Sema::ActOnTagStartDefinition(Scope *S, Decl *TagD) { AddPushedVisibilityAttribute(Tag); } +bool Sema::ActOnDuplicateDefinition(DeclSpec &DS, Decl *Prev, + SkipBodyInfo &SkipBody) { + if (!hasStructuralCompatLayout(Prev, SkipBody.New)) + return false; + + // Make the previous decl visible. + makeMergedDefinitionVisible(SkipBody.Previous); + return true; +} + Decl *Sema::ActOnObjCContainerStartDefinition(Decl *IDecl) { assert(isa<ObjCContainerDecl>(IDecl) && "ActOnObjCContainerStartDefinition - Not ObjCContainerDecl"); @@ -15432,7 +15503,7 @@ Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, Decl *lastEnumConst, // different from T: // - every enumerator of every member of class T that is an unscoped // enumerated type - if (!TheEnumDecl->isScoped()) + if (getLangOpts().CPlusPlus && !TheEnumDecl->isScoped()) DiagnoseClassNameShadow(TheEnumDecl->getDeclContext(), DeclarationNameInfo(Id, IdLoc)); |