<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/70173>70173</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            [C++20] [Modules] Is it a real ODR violation to have non-inline template forward decl followed with inline template decl?
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            clang:modules
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          ChuanqiXu9
      </td>
    </tr>
</table>

<pre>
    Reproducer:

```
// RUN: rm -rf %t
// RUN: split-file %s %t
// RUN: cd %t
//
// RUN: %clang_cc1 -std=c++20 %t/bar.cppm -emit-module-interface -o %t/bar.pcm
// RUN: %clang_cc1 -std=c++20 %t/foo.cppm -emit-module-interface -o %t/foo.pcm \
// RUN:     -fmodule-file=bar=%t/bar.pcm
// RUN: %clang_cc1 -std=c++20 %t/main.cc -fsyntax-only -verify -fprebuilt-module-path=%t

//--- bar.cppm
module;
#include "templfwd.h"
export module bar;
export using sss::isspace;

//--- foo.cppm
module;
#include "templdecl.h"
export module foo;
import bar;
export using sss::isspace;

//--- main.cc
// expected-no-diagnostics
import foo;
#include "templdecl.h"
int main(void)
{
}

//--- templdecl.h
#ifndef _TEMPDECL_H
#define _TEMPDECL_H
#include "templfwd.h"
namespace sss
{
  template <typename T>
  inline void
  isspace() { return; }
}
#endif

//--- templfwd.h
#ifndef _TEMPFWD_H
#define _TEMPFWD_H
namespace sss
{
  template <typename T>
  void isspace();
}
#endif
```

This was an issue report that I received internally. And it is confusing and I feel it is worth to share it. (I feel github issues is good since others who got confused too can reach this by searching).

The reproducer above was reproduced from the implementation of `isspace()` from locale librarries of libstdc++. The diagnostic message in `main.cc` is "inline declaration of 'isspace' follows non-inline definition".  This was confusing since it looks like a compiler bug. However,  http://eel.is/c++draft/dcl.inline#5 says clearly that it is an ill-formed program. And according to http://eel.is/c++draft/localization, it is the problem of libstdc++ to mark the definition of isspace as `inline`. Since it is not comforming with the standard.

So the behavior of the compiler may be correct.
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJysVk2P2zYQ_TX0ZSBBpix_HHxY2zESoGmLJEV7CyhyKLGhSJWk7Li_vqAky3aymwZNFwvtSvPIefPmcSTmvaoM4pYUO1IcZqwLtXXbfd0x85f6o9vMSisu23fYOis6jo7kTyQ7kOx6XWbj73BLj4Qe4d1vP5P8CVwDiZNAaBGeC_tWq5BIpTFC_Is4Lr4KPQcjtOCameoj53NIfBAkP3BCd4TuaDbsQI8lcylv2wYSbFRIGis6jYkyAZ1kHCGx98iWN_85k7T2OzNFZMsbIMX-uWzxJ5Hj-qgWyQ8lcyQ__E9MG6ZMyjkk0l9MYJ8Ta_QFkhM6JS-QyNZh2Sk91dCyUF-z31uhz5wkCVxFHp4Pq0i-u8JyZbjuROw6Ddi0Wp5FWhNKBwB-bq0LMCyDvtLdQ6TzylTgvY9ezJ-U9y3jdwm-YHNtxPeyEcj1i3SktdNa1fSRH2c4NuChgfi5RR5QJMYmQrHKWB8U9w-Z78n8eyHKhD4ToeuTVYLQzbhydd1idXie3_1uUzJpBEr4-OHV218Pr_Y_fXw9hQRKZfDZ0Lc7b1iDvVK9dI_kYGDBAgLJ9-HSYkTDB5K_ugKU0TFvX9z10ag8XRO6AbLagcPQOUPyHdzKnf6hORqh5DdUGAg_J8Lx98MLGtxFfrDCWNpjTbf-v1DEF_O5v36olYcz88BM3K1DcNgbKtQswBtwyFGdUEA_rQzT-pLCkxGgAigP3Bo5OJwZAW9AIuoxdLYu1BAs-Jo5BBVSIHQ9QioV6q4cMvqIrqwV4JXhCDbU6DycawuVDWMKFBCsBc4MOGS8hhCJlxfwyByvlakI3aSPlfW1jO8qYKU9YV_p9FCAdLaBUCOoptXYoAksKGvASiDL7FHdZTbAteVMI2hVOuacQh_RWpU-iHGcphBz304qNOg9qxCUidtej_gyi4UTSkezxlPF3I0AXU0EViCt1vbswViTTHipjIpwQmkKMLXy1pRBUBVAW_vJg1afEBhw27RKo4Oyq1J4bc94QkfoHqAOoY1zqjc6ok6VJ_Q4liUck_EdIbhOBwqE5gV4dvHANTKnL4Nrhv5HQ2mdSOsaFNA6WznWDN5hnFsnIsFgvy9nL7r6mw3V7scUsXOts6XG5qsmxK0b5j71oJtUETfKCsz3XR5KWWYpvL_KpaLQ0XpNpB-JnlU0c43gAzOCOfHgtfe2j5VYs5OyLiaJ95PQDbtAGe-dQx7SmdjmYpNv2Ay38-VmTWmWL_JZvcVFsc44ZijlJt8UBV2uy3mx5OWmnGfZaj1TW5rRfJ7RIlsVlObpcrGRfDlfLuZywZfFnCwybJjSqdanJrWumvVnbLvK5qt8plmJ2vcfeJT2XwMkH1-DPo7e4jBz27gyKbvKk0WmlQ_-tldQQfffh_vrhwMpDkCK3dtxj-IAb3xUkMVjquGXwzs4KasHV8dusxPem3iac9K6M3OiPwWj21EMsn8JjRCSH2ed09voHj_ZZxgrKbdN9Iw-Xf8krbN_Io9OGkYOocdekX8CAAD__-wFYGQ">