diff options
Diffstat (limited to 'lib/Sema/SemaDecl.cpp')
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 182 |
1 files changed, 148 insertions, 34 deletions
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index e340456bc6da..ef8a408f90de 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -1327,15 +1327,17 @@ void Sema::ActOnExitFunctionContext() { /// overloaded function declaration or has the "overloadable" /// attribute. static bool AllowOverloadingOfFunction(LookupResult &Previous, - ASTContext &Context) { + ASTContext &Context, + const FunctionDecl *New) { if (Context.getLangOpts().CPlusPlus) return true; if (Previous.getResultKind() == LookupResult::FoundOverloaded) return true; - return (Previous.getResultKind() == LookupResult::Found - && Previous.getFoundDecl()->hasAttr<OverloadableAttr>()); + return Previous.getResultKind() == LookupResult::Found && + (Previous.getFoundDecl()->hasAttr<OverloadableAttr>() || + New->hasAttr<OverloadableAttr>()); } /// Add this decl to the scope shadowed decl chains. @@ -2933,6 +2935,41 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, New->dropAttr<InternalLinkageAttr>(); } + if (!getLangOpts().CPlusPlus) { + bool OldOvl = Old->hasAttr<OverloadableAttr>(); + if (OldOvl != New->hasAttr<OverloadableAttr>() && !Old->isImplicit()) { + Diag(New->getLocation(), diag::err_attribute_overloadable_mismatch) + << New << OldOvl; + + // Try our best to find a decl that actually has the overloadable + // attribute for the note. In most cases (e.g. programs with only one + // broken declaration/definition), this won't matter. + // + // FIXME: We could do this if we juggled some extra state in + // OverloadableAttr, rather than just removing it. + const Decl *DiagOld = Old; + if (OldOvl) { + auto OldIter = llvm::find_if(Old->redecls(), [](const Decl *D) { + const auto *A = D->getAttr<OverloadableAttr>(); + return A && !A->isImplicit(); + }); + // If we've implicitly added *all* of the overloadable attrs to this + // chain, emitting a "previous redecl" note is pointless. + DiagOld = OldIter == Old->redecls_end() ? nullptr : *OldIter; + } + + if (DiagOld) + Diag(DiagOld->getLocation(), + diag::note_attribute_overloadable_prev_overload) + << OldOvl; + + if (OldOvl) + New->addAttr(OverloadableAttr::CreateImplicit(Context)); + else + New->dropAttr<OverloadableAttr>(); + } + } + // If a function is first declared with a calling convention, but is later // declared or defined without one, all following decls assume the calling // convention of the first. @@ -9179,6 +9216,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, bool Redeclaration = false; NamedDecl *OldDecl = nullptr; + bool MayNeedOverloadableChecks = false; // Merge or overload the declaration with an existing declaration of // the same name, if appropriate. @@ -9187,13 +9225,14 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, // a declaration that requires merging. If it's an overload, // there's no more work to do here; we'll just add the new // function to the scope. - if (!AllowOverloadingOfFunction(Previous, Context)) { + if (!AllowOverloadingOfFunction(Previous, Context, NewFD)) { NamedDecl *Candidate = Previous.getRepresentativeDecl(); if (shouldLinkPossiblyHiddenDecl(Candidate, NewFD)) { Redeclaration = true; OldDecl = Candidate; } } else { + MayNeedOverloadableChecks = true; switch (CheckOverload(S, NewFD, Previous, OldDecl, /*NewIsUsingDecl*/ false)) { case Ovl_Match: @@ -9208,18 +9247,6 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, Redeclaration = false; break; } - - if (!getLangOpts().CPlusPlus && !NewFD->hasAttr<OverloadableAttr>()) { - // If a function name is overloadable in C, then every function - // with that name must be marked "overloadable". - Diag(NewFD->getLocation(), diag::err_attribute_overloadable_missing) - << Redeclaration << NewFD; - NamedDecl *OverloadedDecl = - Redeclaration ? OldDecl : Previous.getRepresentativeDecl(); - Diag(OverloadedDecl->getLocation(), - diag::note_attribute_overloadable_prev_overload); - NewFD->addAttr(OverloadableAttr::CreateImplicit(Context)); - } } } @@ -9234,15 +9261,10 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, MergeTypeWithPrevious = false; // ... except in the presence of __attribute__((overloadable)). - if (OldDecl->hasAttr<OverloadableAttr>()) { - if (!getLangOpts().CPlusPlus && !NewFD->hasAttr<OverloadableAttr>()) { - Diag(NewFD->getLocation(), diag::err_attribute_overloadable_missing) - << Redeclaration << NewFD; - Diag(Previous.getFoundDecl()->getLocation(), - diag::note_attribute_overloadable_prev_overload); - NewFD->addAttr(OverloadableAttr::CreateImplicit(Context)); - } + if (OldDecl->hasAttr<OverloadableAttr>() || + NewFD->hasAttr<OverloadableAttr>()) { if (IsOverload(NewFD, cast<FunctionDecl>(OldDecl), false)) { + MayNeedOverloadableChecks = true; Redeclaration = false; OldDecl = nullptr; } @@ -9337,6 +9359,29 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, NewFD->setAccess(OldDecl->getAccess()); } } + } else if (!getLangOpts().CPlusPlus && MayNeedOverloadableChecks && + !NewFD->getAttr<OverloadableAttr>()) { + assert((Previous.empty() || + llvm::any_of(Previous, + [](const NamedDecl *ND) { + return ND->hasAttr<OverloadableAttr>(); + })) && + "Non-redecls shouldn't happen without overloadable present"); + + auto OtherUnmarkedIter = llvm::find_if(Previous, [](const NamedDecl *ND) { + const auto *FD = dyn_cast<FunctionDecl>(ND); + return FD && !FD->hasAttr<OverloadableAttr>(); + }); + + if (OtherUnmarkedIter != Previous.end()) { + Diag(NewFD->getLocation(), + diag::err_attribute_overloadable_multiple_unmarked_overloads); + Diag((*OtherUnmarkedIter)->getLocation(), + diag::note_attribute_overloadable_prev_overload) + << false; + + NewFD->addAttr(OverloadableAttr::CreateImplicit(Context)); + } } // Semantic checking for this function declaration (in isolation). @@ -11100,9 +11145,7 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { bool IsGlobal = GlobalStorage && !var->isStaticLocal(); QualType baseType = Context.getBaseElementType(type); - if (!var->getDeclContext()->isDependentContext() && - Init && !Init->isValueDependent()) { - + if (Init && !Init->isValueDependent()) { if (var->isConstexpr()) { SmallVector<PartialDiagnosticAt, 8> Notes; if (!var->evaluateValue(Notes) || !var->isInitICE()) { @@ -11932,7 +11975,7 @@ Sema::CheckForFunctionRedefinition(FunctionDecl *FD, if (canRedefineFunction(Definition, getLangOpts())) return; - // Don't emit an error when this is redifinition of a typo-corrected + // Don't emit an error when this is redefinition of a typo-corrected // definition. if (TypoCorrectedFunctionDefinitions.count(Definition)) return; @@ -13190,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'). @@ -13595,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 @@ -13832,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 @@ -13968,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"); @@ -15389,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)); |