summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/AST/Decl.cpp12
-rw-r--r--clang/lib/Sema/Sema.cpp79
-rw-r--r--clang/lib/Sema/SemaDecl.cpp14
-rw-r--r--clang/lib/Sema/SemaExpr.cpp2
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);
OpenPOWER on IntegriCloud