summaryrefslogtreecommitdiffstats
path: root/clang/lib/Sema/SemaDecl.cpp
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2017-05-09 23:02:10 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2017-05-09 23:02:10 +0000
commit77e9e84a8e267597f4832980a9d84b1bc3598b3c (patch)
treeb1e59f0648d45c55970124a964a4d59192f1b7cb /clang/lib/Sema/SemaDecl.cpp
parentc3d677f9d9bae73b34dae09e0e0afba29eed18a3 (diff)
downloadbcm5719-llvm-77e9e84a8e267597f4832980a9d84b1bc3598b3c.tar.gz
bcm5719-llvm-77e9e84a8e267597f4832980a9d84b1bc3598b3c.zip
Don't mark a member as a member specialization until we know we're keeping the specialization.
This improves our behavior in a few ways: * We now guarantee that if a member is marked as being a member specialization, there will actually be a member specialization declaration somewhere on its redeclaration chain. This fixes a crash in modules builds where we would try to check that there was a visible declaration of the member specialization and be surprised to not find any declaration of it at all. * We don't set the source location of the in-class declaration of the member specialization to the out-of-line declaration's location until we have actually finished merging them. This fixes some very silly looking diagnostics, where we'd point a "previous declaration is here" note at the same declaration we're complaining about. Ideally we wouldn't mess with the prior declaration's location at all, but too much code assumes that the first declaration of an entity is a reasonable thing to use as an indication of where it was declared, and that's not really true for a member specialization unless we fake it like this. llvm-svn: 302596
Diffstat (limited to 'clang/lib/Sema/SemaDecl.cpp')
-rw-r--r--clang/lib/Sema/SemaDecl.cpp25
1 files changed, 22 insertions, 3 deletions
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 2d15c75f48f..367a1346a7e 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -1488,6 +1488,11 @@ bool Sema::ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const {
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
if (FD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation)
return false;
+ // A non-out-of-line declaration of a member specialization was implicitly
+ // instantiated; it's the out-of-line declaration that we're interested in.
+ if (FD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization &&
+ FD->getMemberSpecializationInfo() && !FD->isOutOfLine())
+ return false;
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
if (MD->isVirtual() || IsDisallowedCopyOrAssign(MD))
@@ -1514,6 +1519,10 @@ bool Sema::ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const {
if (VD->isStaticDataMember() &&
VD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation)
return false;
+ if (VD->isStaticDataMember() &&
+ VD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization &&
+ VD->getMemberSpecializationInfo() && !VD->isOutOfLine())
+ return false;
if (VD->isInline() && !isMainFileLoc(*this, VD->getLocation()))
return false;
@@ -6706,6 +6715,9 @@ NamedDecl *Sema::ActOnVariableDeclarator(
return NewTemplate;
}
+ if (IsMemberSpecialization && !NewVD->isInvalidDecl())
+ CompleteMemberSpecialization(NewVD, Previous);
+
return NewVD;
}
@@ -8919,13 +8931,17 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
}
+ MarkUnusedFileScopedDecl(NewFD);
+
if (getLangOpts().CPlusPlus) {
if (FunctionTemplate) {
if (NewFD->isInvalidDecl())
FunctionTemplate->setInvalidDecl();
- MarkUnusedFileScopedDecl(NewFD);
return FunctionTemplate;
}
+
+ if (isMemberSpecialization && !NewFD->isInvalidDecl())
+ CompleteMemberSpecialization(NewFD, Previous);
}
if (NewFD->hasAttr<OpenCLKernelAttr>()) {
@@ -8965,8 +8981,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
}
- MarkUnusedFileScopedDecl(NewFD);
-
// Here we have an function template explicit specialization at class scope.
// The actually specialization will be postponed to template instatiation
// time via the ClassScopeFunctionSpecializationDecl node.
@@ -9183,7 +9197,9 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
if (OldTemplateDecl->getTemplatedDecl()->isDeleted()) {
FunctionDecl *const OldTemplatedDecl =
OldTemplateDecl->getTemplatedDecl();
+ // FIXME: This assert will not hold in the presence of modules.
assert(OldTemplatedDecl->getCanonicalDecl() == OldTemplatedDecl);
+ // FIXME: We need an update record for this AST mutation.
OldTemplatedDecl->setDeletedAsWritten(false);
}
}
@@ -13752,6 +13768,9 @@ CreateNewDecl:
// record.
AddPushedVisibilityAttribute(New);
+ if (isMemberSpecialization && !New->isInvalidDecl())
+ CompleteMemberSpecialization(New, Previous);
+
OwnedDecl = true;
// In C++, don't return an invalid declaration. We can't recover well from
// the cases where we make the type anonymous.
OpenPOWER on IntegriCloud