diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/AST/Decl.cpp | 12 | ||||
-rw-r--r-- | clang/lib/Sema/Sema.cpp | 79 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 14 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 2 |
4 files changed, 68 insertions, 39 deletions
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 0a4c4a4a776..c3e3de1e22b 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -721,8 +721,7 @@ LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl *D, // because of this, but unique-external linkage suits us. if (Context.getLangOpts().CPlusPlus && !isFirstInExternCContext(Var)) { LinkageInfo TypeLV = getLVForType(*Var->getType(), computation); - if (TypeLV.getLinkage() != ExternalLinkage && - TypeLV.getLinkage() != ModuleLinkage) + if (!isExternallyVisible(TypeLV.getLinkage())) return LinkageInfo::uniqueExternal(); if (!LV.isVisibilityExplicit()) LV.mergeVisibility(TypeLV); @@ -772,7 +771,7 @@ LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl *D, QualType TypeAsWritten = Function->getType(); if (TypeSourceInfo *TSI = Function->getTypeSourceInfo()) TypeAsWritten = TSI->getType(); - if (TypeAsWritten->getLinkage() == UniqueExternalLinkage) + if (!isExternallyVisible(TypeAsWritten->getLinkage())) return LinkageInfo::uniqueExternal(); } @@ -909,7 +908,7 @@ LinkageComputer::getLVForClassMember(const NamedDecl *D, const NamedDecl *explicitSpecSuppressor = nullptr; if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) { - // If the type of the function uses a type with unique-external + // If the type of the function uses a type that has non-externally-visible // linkage, it's not legally usable from outside this translation unit. // But only look at the type-as-written. If this function has an // auto-deduced return type, we can't compute the linkage of that type @@ -922,7 +921,7 @@ LinkageComputer::getLVForClassMember(const NamedDecl *D, QualType TypeAsWritten = MD->getType(); if (TypeSourceInfo *TSI = MD->getTypeSourceInfo()) TypeAsWritten = TSI->getType(); - if (TypeAsWritten->getLinkage() == UniqueExternalLinkage) + if (!isExternallyVisible(TypeAsWritten->getLinkage())) return LinkageInfo::uniqueExternal(); } // If this is a method template specialization, use the linkage for @@ -1119,6 +1118,9 @@ LinkageInfo LinkageComputer::getLVForClosure(const DeclContext *DC, Decl *ContextDecl, LVComputationKind computation) { // This lambda has its linkage/visibility determined by its owner. + // FIXME: This is wrong. A lambda never formally has linkage; if this + // calculation determines the lambda has external linkage, it should be + // downgraded to VisibleNoLinkage. if (ContextDecl) { if (isa<ParmVarDecl>(ContextDecl)) DC = ContextDecl->getDeclContext()->getRedeclContext(); diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 66cb4976dac..62692519674 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -582,6 +582,23 @@ static bool ShouldRemoveFromUnused(Sema *SemaRef, const DeclaratorDecl *D) { return false; } +static bool isFunctionOrVarDeclExternC(NamedDecl *ND) { + if (auto *FD = dyn_cast<FunctionDecl>(ND)) + return FD->isExternC(); + return cast<VarDecl>(ND)->isExternC(); +} + +/// Determine whether ND is an external-linkage function or variable whose +/// type has no linkage. +bool Sema::isExternalWithNoLinkageType(ValueDecl *VD) { + // Note: it's not quite enough to check whether VD has UniqueExternalLinkage, + // because we also want to catch the case where its type has VisibleNoLinkage, + // which does not affect the linkage of VD. + return getLangOpts().CPlusPlus && VD->hasExternalFormalLinkage() && + !isExternalFormalLinkage(VD->getType()->getLinkage()) && + !isFunctionOrVarDeclExternC(VD); +} + /// Obtains a sorted list of functions and variables that are undefined but /// ODR-used. void Sema::getUndefinedButUsed( @@ -598,17 +615,27 @@ void Sema::getUndefinedButUsed( if (isa<CXXDeductionGuideDecl>(ND)) continue; + if (ND->hasAttr<DLLImportAttr>() || ND->hasAttr<DLLExportAttr>()) { + // An exported function will always be emitted when defined, so even if + // the function is inline, it doesn't have to be emitted in this TU. An + // imported function implies that it has been exported somewhere else. + continue; + } + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) { if (FD->isDefined()) continue; if (FD->isExternallyVisible() && + !isExternalWithNoLinkageType(FD) && !FD->getMostRecentDecl()->isInlined()) continue; } else { auto *VD = cast<VarDecl>(ND); if (VD->hasDefinition() != VarDecl::DeclarationOnly) continue; - if (VD->isExternallyVisible() && !VD->getMostRecentDecl()->isInline()) + if (VD->isExternallyVisible() && + !isExternalWithNoLinkageType(VD) && + !VD->getMostRecentDecl()->isInline()) continue; } @@ -626,33 +653,43 @@ static void checkUndefinedButUsed(Sema &S) { S.getUndefinedButUsed(Undefined); if (Undefined.empty()) return; - for (SmallVectorImpl<std::pair<NamedDecl *, SourceLocation> >::iterator - I = Undefined.begin(), E = Undefined.end(); I != E; ++I) { - NamedDecl *ND = I->first; - - if (ND->hasAttr<DLLImportAttr>() || ND->hasAttr<DLLExportAttr>()) { - // An exported function will always be emitted when defined, so even if - // the function is inline, it doesn't have to be emitted in this TU. An - // imported function implies that it has been exported somewhere else. - continue; - } - - if (!ND->isExternallyVisible()) { - S.Diag(ND->getLocation(), diag::warn_undefined_internal) - << isa<VarDecl>(ND) << ND; - } else if (auto *FD = dyn_cast<FunctionDecl>(ND)) { + for (auto Undef : Undefined) { + ValueDecl *VD = cast<ValueDecl>(Undef.first); + SourceLocation UseLoc = Undef.second; + + if (S.isExternalWithNoLinkageType(VD)) { + // C++ [basic.link]p8: + // A type without linkage shall not be used as the type of a variable + // or function with external linkage unless + // -- the entity has C language linkage + // -- the entity is not odr-used or is defined in the same TU + // + // As an extension, accept this in cases where the type is externally + // visible, since the function or variable actually can be defined in + // another translation unit in that case. + S.Diag(VD->getLocation(), isExternallyVisible(VD->getType()->getLinkage()) + ? diag::ext_undefined_internal_type + : diag::err_undefined_internal_type) + << isa<VarDecl>(VD) << VD; + } else if (!VD->isExternallyVisible()) { + // FIXME: We can promote this to an error. The function or variable can't + // be defined anywhere else, so the program must necessarily violate the + // one definition rule. + S.Diag(VD->getLocation(), diag::warn_undefined_internal) + << isa<VarDecl>(VD) << VD; + } else if (auto *FD = dyn_cast<FunctionDecl>(VD)) { (void)FD; assert(FD->getMostRecentDecl()->isInlined() && "used object requires definition but isn't inline or internal?"); // FIXME: This is ill-formed; we should reject. - S.Diag(ND->getLocation(), diag::warn_undefined_inline) << ND; + S.Diag(VD->getLocation(), diag::warn_undefined_inline) << VD; } else { - assert(cast<VarDecl>(ND)->getMostRecentDecl()->isInline() && + assert(cast<VarDecl>(VD)->getMostRecentDecl()->isInline() && "used var requires definition but isn't inline or internal?"); - S.Diag(ND->getLocation(), diag::err_undefined_inline_var) << ND; + S.Diag(VD->getLocation(), diag::err_undefined_inline_var) << VD; } - if (I->second.isValid()) - S.Diag(I->second, diag::note_used_here); + if (UseLoc.isValid()) + S.Diag(UseLoc, diag::note_used_here); } S.UndefinedButUsed.clear(); diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 2cd93364869..389cd7ab737 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -3827,7 +3827,7 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { } } - // If this redeclaration makes the function inline, we may need to add it to + // If this redeclaration makes the variable inline, we may need to add it to // UndefinedButUsed. if (!Old->isInline() && New->isInline() && Old->isUsed(false) && !Old->getDefinition() && !New->isThisDeclarationADefinition()) @@ -12329,18 +12329,6 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, } } - // The only way to be included in UndefinedButUsed is if there is an - // ODR use before the definition. Avoid the expensive map lookup if this - // is the first declaration. - if (!FD->isFirstDecl() && FD->getPreviousDecl()->isUsed()) { - if (!FD->isExternallyVisible()) - UndefinedButUsed.erase(FD); - else if (FD->isInlined() && - !LangOpts.GNUInline && - (!FD->getPreviousDecl()->hasAttr<GNUInlineAttr>())) - UndefinedButUsed.erase(FD); - } - // If the function implicitly returns zero (like 'main') or is naked, // don't complain about missing return statements. if (FD->hasImplicitReturnZero() || FD->hasAttr<NakedAttr>()) diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index c1b2ad0d738..46853dd32c5 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -13897,6 +13897,8 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, !LangOpts.GNUInline && !Func->getMostRecentDecl()->hasAttr<GNUInlineAttr>()) UndefinedButUsed.insert(std::make_pair(Func->getCanonicalDecl(), Loc)); + else if (isExternalWithNoLinkageType(Func)) + UndefinedButUsed.insert(std::make_pair(Func->getCanonicalDecl(), Loc)); } Func->markUsed(Context); |