================ @@ -10057,15 +10057,18 @@ void ASTReader::finishPendingActions() { // For a function defined inline within a class template, force the // canonical definition to be the one inside the canonical definition of // the template. This ensures that we instantiate from a correct view - // of the template. + // of the template. This behaviour seems to be important only for inline + // friend functions. For normal member functions, it might results in + // selecting canonical decl from module A but body from module B. // // Sadly we can't do this more generally: we can't be sure that all // copies of an arbitrary class definition will have the same members // defined (eg, some member functions may not be instantiated, and some // special members may or may not have been implicitly defined). - if (auto *RD = dyn_cast<CXXRecordDecl>(FD->getLexicalParent())) - if (RD->isDependentContext() && !RD->isThisDeclarationADefinition()) - continue; + if (FD->getFriendObjectKind()) ---------------- dmpolukhin wrote:
@ChuanqiXu9 and @ilya-biryukov I'm not sure that I fully understand the example [test case](https://github.com/llvm/llvm-project/blob/main/clang/test/Modules/friend-definition-2.cpp). Do you understand what does the example really do? Things unclear to me marked with `// >>>`. ``` // RUN: %clang_cc1 -std=c++14 -fmodules %s -verify // RUN: %clang_cc1 -std=c++14 -fmodules %s -verify -triple i686-windows // expected-no-diagnostics // >>> it looks like undocumented pragma? #pragma clang module build A // >>> Is it modulemap file syntax? module A {} #pragma clang module contents #pragma clang module begin A // >>> What is the context of this code, is it GMF or part of module A, is it implicitly exported? template<typename T> struct ct { friend auto operator-(ct, ct) { struct X {}; return X(); } void x(); }; #pragma clang module end #pragma clang module endbuild #pragma clang module build B module B {} #pragma clang module contents #pragma clang module begin B // >>> Seems like it was part of GMF otherwise it is duplicating declaration? template<typename T> struct ct { friend auto operator-(ct, ct) { struct X{}; return X(); } void x(); }; inline auto f() { return ct<float>() - ct<float>(); } #pragma clang module end #pragma clang module endbuild // >>> Seems like here we are in different translation unit // Force the definition of ct in module A to be the primary definition. #pragma clang module import A // >>> Why does it define something from module A !? // >>> Should we see here error like: `declaration of 'x' in the global module follows declaration in module A` template<typename T> void ct<T>::x() {} // Attempt to cause the definition of operator- in the ct primary template in // module B to be the primary definition of that function. If that happens, // we'll be left with a class template ct that appears to not contain a // definition of the inline friend function. #pragma clang module import B auto v = f(); ct<int> make(); void h() { make() - make(); } ``` https://github.com/llvm/llvm-project/pull/111992 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits