summaryrefslogtreecommitdiffstats
path: root/clang/lib/Sema
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r--clang/lib/Sema/SemaDecl.cpp31
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiateDecl.cpp57
2 files changed, 47 insertions, 41 deletions
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index a176964fc2f..62fd0207715 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -12283,9 +12283,36 @@ Sema::CheckForFunctionRedefinition(FunctionDecl *FD,
const FunctionDecl *EffectiveDefinition,
SkipBodyInfo *SkipBody) {
const FunctionDecl *Definition = EffectiveDefinition;
+ if (!Definition && !FD->isDefined(Definition) && !FD->isCXXClassMember()) {
+ // If this is a friend function defined in a class template, it does not
+ // have a body until it is used, nevertheless it is a definition, see
+ // [temp.inst]p2:
+ //
+ // ... for the purpose of determining whether an instantiated redeclaration
+ // is valid according to [basic.def.odr] and [class.mem], a declaration that
+ // corresponds to a definition in the template is considered to be a
+ // definition.
+ //
+ // The following code must produce redefinition error:
+ //
+ // template<typename T> struct C20 { friend void func_20() {} };
+ // C20<int> c20i;
+ // void func_20() {}
+ //
+ for (auto I : FD->redecls()) {
+ if (I != FD && !I->isInvalidDecl() &&
+ I->getFriendObjectKind() != Decl::FOK_None) {
+ if (FunctionDecl *Original = I->getInstantiatedFromMemberFunction()) {
+ if (Original->isThisDeclarationADefinition()) {
+ Definition = I;
+ break;
+ }
+ }
+ }
+ }
+ }
if (!Definition)
- if (!FD->isDefined(Definition))
- return;
+ return;
if (canRedefineFunction(Definition, getLangOpts()))
return;
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index d87f9dbbbea..800956dd535 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1806,45 +1806,24 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
// apply to non-template function declarations and definitions also apply
// to these implicit definitions.
if (D->isThisDeclarationADefinition()) {
- // Check for a function body.
- const FunctionDecl *Definition = nullptr;
- if (Function->isDefined(Definition) &&
- Definition->getTemplateSpecializationKind() == TSK_Undeclared) {
- SemaRef.Diag(Function->getLocation(), diag::err_redefinition)
- << Function->getDeclName();
- SemaRef.Diag(Definition->getLocation(), diag::note_previous_definition);
- }
- // Check for redefinitions due to other instantiations of this or
- // a similar friend function.
- else for (auto R : Function->redecls()) {
- if (R == Function)
- continue;
-
- // If some prior declaration of this function has been used, we need
- // to instantiate its definition.
- if (!QueuedInstantiation && R->isUsed(false)) {
- if (MemberSpecializationInfo *MSInfo =
- Function->getMemberSpecializationInfo()) {
- if (MSInfo->getPointOfInstantiation().isInvalid()) {
- SourceLocation Loc = R->getLocation(); // FIXME
- MSInfo->setPointOfInstantiation(Loc);
- SemaRef.PendingLocalImplicitInstantiations.push_back(
- std::make_pair(Function, Loc));
- QueuedInstantiation = true;
- }
- }
- }
-
- // If some prior declaration of this function was a friend with an
- // uninstantiated definition, reject it.
- if (R->getFriendObjectKind()) {
- if (const FunctionDecl *RPattern =
- R->getTemplateInstantiationPattern()) {
- if (RPattern->isDefined(RPattern)) {
- SemaRef.Diag(Function->getLocation(), diag::err_redefinition)
- << Function->getDeclName();
- SemaRef.Diag(R->getLocation(), diag::note_previous_definition);
- break;
+ SemaRef.CheckForFunctionRedefinition(Function);
+ if (!Function->isInvalidDecl()) {
+ for (auto R : Function->redecls()) {
+ if (R == Function)
+ continue;
+
+ // If some prior declaration of this function has been used, we need
+ // to instantiate its definition.
+ if (!QueuedInstantiation && R->isUsed(false)) {
+ if (MemberSpecializationInfo *MSInfo =
+ Function->getMemberSpecializationInfo()) {
+ if (MSInfo->getPointOfInstantiation().isInvalid()) {
+ SourceLocation Loc = R->getLocation(); // FIXME
+ MSInfo->setPointOfInstantiation(Loc);
+ SemaRef.PendingLocalImplicitInstantiations.push_back(
+ std::make_pair(Function, Loc));
+ QueuedInstantiation = true;
+ }
}
}
}
OpenPOWER on IntegriCloud