@@ -1719,6 +1719,80 @@ bool Sema::CheckRedeclarationInModule(NamedDecl *New, NamedDecl *Old) {
17191719 return false;
17201720}
17211721
1722+ // Check the redefinition in C++20 Modules.
1723+ //
1724+ // [basic.def.odr]p14:
1725+ // For any definable item D with definitions in multiple translation units,
1726+ // - if D is a non-inline non-templated function or variable, or
1727+ // - if the definitions in different translation units do not satisfy the
1728+ // following requirements,
1729+ // the program is ill-formed; a diagnostic is required only if the definable
1730+ // item is attached to a named module and a prior definition is reachable at
1731+ // the point where a later definition occurs.
1732+ // - Each such definition shall not be attached to a named module
1733+ // ([module.unit]).
1734+ // - Each such definition shall consist of the same sequence of tokens, ...
1735+ // ...
1736+ //
1737+ // Return true if the redefinition is not allowed. Return false otherwise.
1738+ bool Sema::IsRedefinitionInModule(const NamedDecl *New,
1739+ const NamedDecl *Old) const {
1740+ assert(getASTContext().isSameEntity(New, Old) &&
1741+ "New and Old are not the same definition, we should diagnostic it "
1742+ "immediately instead of checking it.");
1743+ assert(const_cast<Sema *>(this)->isReachable(New) &&
1744+ const_cast<Sema *>(this)->isReachable(Old) &&
1745+ "We shouldn't see unreachable definitions here.");
1746+
1747+ Module *NewM = New->getOwningModule();
1748+ Module *OldM = Old->getOwningModule();
1749+
1750+ // We only checks for named modules here. The header like modules is skipped.
1751+ // FIXME: This is not right if we import the header like modules in the module
1752+ // purview.
1753+ //
1754+ // For example, assuming "header.h" provides definition for `D`.
1755+ // ```C++
1756+ // //--- M.cppm
1757+ // export module M;
1758+ // import "header.h"; // or #include "header.h" but import it by clang modules
1759+ // actually.
1760+ //
1761+ // //--- Use.cpp
1762+ // import M;
1763+ // import "header.h"; // or uses clang modules.
1764+ // ```
1765+ //
1766+ // In this case, `D` has multiple definitions in multiple TU (M.cppm and
1767+ // Use.cpp) and `D` is attached to a named module `M`. The compiler should
1768+ // reject it. But the current implementation couldn't detect the case since we
1769+ // don't record the information about the importee modules.
1770+ //
1771+ // But this might not be painful in practice. Since the design of C++20 Named
1772+ // Modules suggests us to use headers in global module fragment instead of
1773+ // module purview.
1774+ if (NewM && NewM->isHeaderLikeModule())
1775+ NewM = nullptr;
1776+ if (OldM && OldM->isHeaderLikeModule())
1777+ OldM = nullptr;
1778+
1779+ if (!NewM && !OldM)
1780+ return true;
1781+
1782+ // [basic.def.odr]p14.3
1783+ // Each such definition shall not be attached to a named module
1784+ // ([module.unit]).
1785+ if ((NewM && NewM->isModulePurview()) || (OldM && OldM->isModulePurview()))
1786+ return true;
1787+
1788+ // Then New and Old lives in the same TU if their share one same module unit.
1789+ if (NewM)
1790+ NewM = NewM->getTopLevelModule();
1791+ if (OldM)
1792+ OldM = OldM->getTopLevelModule();
1793+ return OldM == NewM;
1794+ }
1795+
17221796static bool isUsingDecl(NamedDecl *D) {
17231797 return isa<UsingShadowDecl>(D) ||
17241798 isa<UnresolvedUsingTypenameDecl>(D) ||
0 commit comments