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));  | 
