Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1055,7 +1055,8 @@ void ASTContext::PrintStats() const {
void ASTContext::mergeDefinitionIntoModule(NamedDecl *ND, Module *M,
bool NotifyListeners) {
if (NotifyListeners)
if (auto *Listener = getASTMutationListener())
if (auto *Listener = getASTMutationListener();
Listener && !ND->isUnconditionallyVisible())
Listener->RedefinedHiddenDefinition(ND, M);

MergedDefModules[cast<NamedDecl>(ND->getCanonicalDecl())].push_back(M);
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/Serialization/ASTReaderDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3746,6 +3746,11 @@ void ASTDeclReader::checkMultipleDefinitionInNamedModules(ASTReader &Reader,
Func && Func->getTemplateSpecializationInfo())
return;

// The module ownership of in-class friend declaration is not straightforward.
// Avoid diagnosing such cases.
if (D->getFriendObjectKind() || Previous->getFriendObjectKind())
return;

Module *M = Previous->getOwningModule();
if (!M)
return;
Expand Down
57 changes: 57 additions & 0 deletions clang/test/Modules/pr125521.cppm
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// RUN: rm -rf %t
// RUN: mkdir -p %t
// RUN: split-file %s %t
//
// RUN: %clang_cc1 -std=c++20 %t/mod2.cppm -emit-module-interface -o %t/mod2.pcm
// RUN: %clang_cc1 -std=c++20 %t/mod1.cppm -emit-module-interface -o %t/mod1.pcm \
// RUN: -fmodule-file=Mod2=%t/mod2.pcm
// RUN: %clang_cc1 -std=c++20 %t/test.cc -fmodule-file=Mod2=%t/mod2.pcm -fmodule-file=Mod=%t/mod1.pcm \
// RUN: -fsyntax-only -verify

// RUN: %clang_cc1 -std=c++20 %t/mod2.cppm -emit-module-interface -o %t/mod2.pcm
// RUN: %clang_cc1 -std=c++20 %t/mod1.cppm -emit-module-interface -o %t/mod1.pcm \
// RUN: -fmodule-file=Mod2=%t/mod2.pcm
// RUN: %clang_cc1 -std=c++20 %t/mod1.pcm -fmodule-file=Mod2=%t/mod2.pcm -emit-llvm -o - \
// RUN: | FileCheck %t/mod1.cppm

//--- hello.h
template <typename V> int get() noexcept {return 0;};

template <typename T>
class List
{
template <typename V> friend int get() noexcept;
};

//--- mod2.cppm
module;
#include "hello.h"
export module Mod2;
export const char *modFn2() {
List<int> a;
return "hello";
}

//--- mod1.cppm
module;
#include "hello.h"
export module Mod;
import Mod2;
export extern "C" const char *modFn() {
List<int> a;
List<double> b;
return modFn2();
}

// Fine enough to check it won't crash.
// CHECK: define {{.*}}@modFn

//--- test.cc
// expected-no-diagnostics
import Mod;
import Mod2;

void test() {
modFn();
modFn2();
}
Loading