[clang] [clang][NFC] Add test for CWG issues about linkage in cross-TU context (PR #113736)

Vlad Serebrennikov via cfe-commits cfe-commits at lists.llvm.org
Fri Oct 25 13:06:50 PDT 2024


https://github.com/Endilll created https://github.com/llvm/llvm-project/pull/113736

CWG issues

[CWG279](https://cplusplus.github.io/CWG/issues/279.html) Correspondence of "names for linkage purposes"
====================

[P1787R6](https://wg21.link/p1787r6):
> CWG1884, CWG279, and CWG338 are resolved by defining entity identity explicitly.

In both cases discussed in the issue, declaration matching succeeds per [[basic.link]/8](https://eel.is/c++draft/basic.link#8), thanks to the
> considering declarations of unnamed types to introduce their names for linkage purposes, if any ([dcl.typedef], [dcl.enum])

and

> they both declare names with external linkage

parts. Which means that both pairs of declarations of `S` and `S2` declare the same entity. [[basic.link]/11](https://eel.is/c++draft/basic.link#11) is also satisfied, because in all causes type is declared.

Then cases diverge. `S` is a pair of a forward declaration and a definition, which means it's not a subject to [[basic.def.odr]/15](https://eel.is/c++draft/basic.def.odr#15), hence it's well-formed. Whereas `S2` is a pair of two definitions, so they are subjects to [[basic.def.odr]/15](https://eel.is/c++draft/basic.def.odr#15), which they do not satisfy due to the violation of the following requirement:

> — Each such definition shall consist of the same sequence of tokens, <...>

Because per [[class.pre/2]](https://eel.is/c++draft/class#pre-2), class definition is class-specifier, which includes class-head, but class-head is different between definitions.



[CWG338](https://cplusplus.github.io/CWG/issues/338.html) Enumerator name with linkage used as class name in other translation unit 
====================

[P1787R6](https://wg21.link/p1787r6):
> CWG1884, CWG279, and CWG338 are resolved by defining entity identity explicitly.

I believe this CWG issue points to the same underlying issue with old [basic.link]/9 as CWG1884 (see below), so I'm calling it a duplicate of CWG1884. Cases described there are a part of an extensive CWG1884 test. Also worth noting that enumerators don't have linkage these days.



[CWG1884](https://cplusplus.github.io/CWG/issues/1898.html) Unclear requirements for same-named external-linkage entities
====================

[P1787R6](https://wg21.link/p1787r6):
> CWG1884, CWG279, and CWG338 are resolved by defining entity identity explicitly.

[basic.link]/9 quoted in the issue is now split into several pieces.

> Two names that are the same (6.1 [basic.pre])

I believe this is corresponding declarations now, defined in [[basic.scope.scope]/4](https://eel.is/c++draft/basic.scope#scope-4).

> and that are declared in different scopes shall denote the same variable, function, type, enumerator, template or namespace if

This is covered by [[basic.link]/11](https://eel.is/c++draft/basic.link#11) after it's determined by [[basic.link]/8](https://eel.is/c++draft/basic.link#8) that two declarations declare the same entity.

>  — both names have external linkage or else both names have internal linkage and are declared in the same translation unit; and
>  — both names refer to members of the same namespace or to members, not by inheritance, of the same class; and

Most of this is covered by [[basic.link]/8](https://eel.is/c++draft/basic.link#8).

>  — when both names denote functions, the parameter-type-lists of the functions (9.3.4.6 [dcl.fct]) are identical; and
>  — when both names denote function templates, the signatures (13.7.7.2 [temp.over.link]) are the same.

This is corresponding overloads now, defined in [[basic.scope.scope]/4](https://eel.is/c++draft/basic.scope#scope-4).

> Among other things, it should be clarified that "declared in" refers to the namespace of which the name is a member, not the lexical scope in which the declaration appears (which affects friend declarations, block-scope extern declarations, and elaborated-type-specifiers).

This is addressed by "have the same target scope" part of [[basic.link]/8](https://eel.is/c++draft/basic.link#8).

The tests basically tests [[basic.link]/11](https://eel.is/c++draft/basic.link#11) from the following standpoint:
> The intent is that this rule prevents declaring a name with extenal linkage to be, for instance, a type in one translation unit and a namespace in a different translation unit.

See the comment in the beginning of the test for details on testing approach. Reviewers are advised to check compiler output for any surprises, but if they are in a hurry, they can search for `FIXME`, `OK`, and `#cwg1884` to see the most of irregularities in Clang behavior across the test (not all of them are incorrect behavior, though).


>From b23ce76d3db79eab6433bef1bd3fc9d26bcb3309 Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Fri, 25 Oct 2024 23:05:06 +0300
Subject: [PATCH] [clang][NFC] Add test for CWG issues about linkage in
 cross-TU context

---
 clang/test/CXX/drs/cwg1884.cpp | 548 +++++++++++++++++++++++++++++++++
 clang/test/CXX/drs/cwg18xx.cpp |   2 +
 clang/test/CXX/drs/cwg279.cpp  |  42 +++
 clang/test/CXX/drs/cwg2xx.cpp  |   2 +
 clang/test/CXX/drs/cwg3xx.cpp  |   2 +
 clang/www/cxx_dr_status.html   |   6 +-
 6 files changed, 599 insertions(+), 3 deletions(-)
 create mode 100644 clang/test/CXX/drs/cwg1884.cpp
 create mode 100644 clang/test/CXX/drs/cwg279.cpp

diff --git a/clang/test/CXX/drs/cwg1884.cpp b/clang/test/CXX/drs/cwg1884.cpp
new file mode 100644
index 00000000000000..d8fa9c4373765c
--- /dev/null
+++ b/clang/test/CXX/drs/cwg1884.cpp
@@ -0,0 +1,548 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: split-file --leading-lines %s %t
+// RUN: %clang_cc1 -std=c++20 -pedantic-errors -fexceptions -fcxx-exceptions %t/cwg1884_A.cppm -triple x86_64-unknown-unknown -emit-module-interface -o %t/cwg1884_A.pcm
+// RUN: %clang_cc1 -std=c++20 -verify=since-cxx20 -pedantic-errors -fexceptions -fcxx-exceptions -triple x86_64-unknown-unknown %t/cwg1884.cpp -fmodule-file=cwg1884_A=%t/cwg1884_A.pcm
+// RUN: %clang_cc1 -std=c++23 -pedantic-errors -fexceptions -fcxx-exceptions %t/cwg1884_A.cppm -triple x86_64-unknown-unknown -emit-module-interface -o %t/cwg1884_A.pcm
+// RUN: %clang_cc1 -std=c++23 -verify=since-cxx20 -pedantic-errors -fexceptions -fcxx-exceptions -triple x86_64-unknown-unknown %t/cwg1884.cpp -fmodule-file=cwg1884_A=%t/cwg1884_A.pcm
+// RUN: %clang_cc1 -std=c++2c -pedantic-errors -fexceptions -fcxx-exceptions %t/cwg1884_A.cppm -triple x86_64-unknown-unknown -emit-module-interface -o %t/cwg1884_A.pcm
+// RUN: %clang_cc1 -std=c++2c -verify=since-cxx20 -pedantic-errors -fexceptions -fcxx-exceptions -triple x86_64-unknown-unknown %t/cwg1884.cpp -fmodule-file=cwg1884_A=%t/cwg1884_A.pcm
+
+// cwg1884: partial
+
+// _N4993_.[basic.link]/11:
+// For any two declarations of an entity E:
+//   — If one declares E to be a variable or function,
+//     the other shall declare E as one of the same type.
+//   — If one declares E to be an enumerator, the other shall do so.
+//   — If one declares E to be a namespace, the other shall do so.
+//   — If one declares E to be a type,
+//     the other shall declare E to be a type of the same kind (9.2.9.5).
+//   — If one declares E to be a class template,
+//     the other shall do so with the same kind and an equivalent template-head (13.7.7.2).
+//     [Note 5 : The declarations can supply different default template arguments. — end note]
+//   — If one declares E to be a function template or a (partial specialization of a) variable template,
+//     the other shall declare E to be one with an equivalent template-head and type.
+//   — If one declares E to be an alias template,
+//     the other shall declare E to be one with an equivalent template-head and defining-type-id.
+//   — If one declares E to be a concept, the other shall do so.
+// Types are compared after all adjustments of types (during which typedefs (9.2.4) are replaced by their definitions);
+// declarations for an array object can specify array types that differ by the presence or absence of a major array bound (9.3.4.5).
+// No diagnostic is required if neither declaration is reachable from the other.
+
+// The structure of the test is the following. First, module cwg1884_A
+// provides all (significant) kinds of entities, each named 'a' through 'k'.
+// Then the .cpp file does MxN kind of testing, where it tests one kind of entity
+// against every other kind.
+
+//--- cwg1884_A.cppm
+export module cwg1884_A;
+
+export {
+int a;
+void b();
+enum E { c };
+namespace d {}
+struct e;
+class f;
+template <typename>
+class g;
+template <typename>
+void h(int);
+template <typename, typename>
+int i;
+template <typename>
+using j = int;
+template <typename>
+concept k = true;
+} // export
+
+
+//--- cwg1884.cpp
+import cwg1884_A;
+
+// int a;
+
+void a();
+// since-cxx20-error at -1 {{redefinition of 'a' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:42 {{previous definition is here}}
+enum Ea {
+  a
+  // since-cxx20-error at -1 {{redefinition of 'a'}}
+  //   since-cxx20-note at cwg1884_A.cppm:42 {{previous definition is here}}
+};
+namespace a {} // #cwg1884-namespace-a
+// since-cxx20-error at -1 {{redefinition of 'a' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:42 {{previous definition is here}}
+struct a;
+// since-cxx20-error at -1 {{redefinition of 'a' as different kind of symbol}}
+//   since-cxx20-note@#cwg1884-namespace-a {{previous definition is here}}
+class a;
+// since-cxx20-error at -1 {{redefinition of 'a' as different kind of symbol}}
+//   since-cxx20-note@#cwg1884-namespace-a {{previous definition is here}}
+template <typename>
+class a;
+// since-cxx20-error at -1 {{redefinition of 'a' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:42 {{previous definition is here}}
+template <typename>
+void a(int);
+// since-cxx20-error at -1 {{redefinition of 'a' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:42 {{previous definition is here}}
+template <typename, typename>
+int a;
+// since-cxx20-error at -1 {{redefinition of 'a' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:42 {{previous definition is here}}
+template <typename T>
+int a<T, int>;
+// since-cxx20-error at -1 {{redefinition of 'a' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:42 {{previous definition is here}}
+// since-cxx20-error at -3 {{expected ';' after top level declarator}}
+template <typename>
+using a = int;
+// since-cxx20-error at -1 {{redefinition of 'a' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:42 {{previous definition is here}}
+template <typename>
+concept a = true;
+// since-cxx20-error at -1 {{redefinition of 'a' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:42 {{previous definition is here}}
+
+
+// void b();
+
+int b;
+// since-cxx20-error at -1 {{redefinition of 'b' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:43 {{previous definition is here}}
+enum Eb {
+  b
+  // since-cxx20-error at -1 {{redefinition of 'b'}}
+  //   since-cxx20-note at cwg1884_A.cppm:43 {{previous definition is here}}
+};
+namespace b {} // #cwg1884-namespace-b
+// since-cxx20-error at -1 {{redefinition of 'b' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:43 {{previous definition is here}}
+struct b;
+// since-cxx20-error at -1 {{redefinition of 'b' as different kind of symbol}}
+//   since-cxx20-note@#cwg1884-namespace-b {{previous definition is here}}
+class b;
+// since-cxx20-error at -1 {{redefinition of 'b' as different kind of symbol}}
+//   since-cxx20-note@#cwg1884-namespace-b {{previous definition is here}}
+template <typename>
+class b;
+// since-cxx20-error at -1 {{redefinition of 'b' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:43 {{previous definition is here}}
+template <typename>
+void b(int); // #cwg1884-func-template-b
+// @-1 OK, a non-corresponding overload
+template <typename, typename>
+int b;
+// since-cxx20-error at -1 {{redefinition of 'b' as different kind of symbol}}
+//   since-cxx20-note@#cwg1884-func-template-b {{previous definition is here}}
+template <typename T>
+int b<T, int>;
+// since-cxx20-error at -1 {{no variable template matches specialization; did you mean to use 'b' as function template instead?}}
+template <typename>
+using b = int;
+// since-cxx20-error at -1 {{redefinition of 'b' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:43 {{previous definition is here}}
+template <typename>
+concept b = true;
+// since-cxx20-error at -1 {{redefinition of 'b' as different kind of symbol}}
+//   since-cxx20-note@#cwg1884-func-template-b {{previous definition is here}}
+
+
+// enum E { c };
+
+int c;
+// since-cxx20-error at -1 {{redefinition of 'c' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:44 {{previous definition is here}}
+void c();
+// since-cxx20-error at -1 {{redefinition of 'c' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:44 {{previous definition is here}}
+namespace c {} // #cwg1884-namespace-c
+// since-cxx20-error at -1 {{redefinition of 'c' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:44 {{previous definition is here}}
+struct c;
+// since-cxx20-error at -1 {{redefinition of 'c' as different kind of symbol}}
+//   since-cxx20-note@#cwg1884-namespace-c {{previous definition is here}}
+class c;
+// since-cxx20-error at -1 {{redefinition of 'c' as different kind of symbol}}
+//   since-cxx20-note@#cwg1884-namespace-c {{previous definition is here}}
+template <typename>
+class c;
+// since-cxx20-error at -1 {{redefinition of 'c' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:44 {{previous definition is here}}
+template <typename>
+void c(int);
+// since-cxx20-error at -1 {{redefinition of 'c' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:44 {{previous definition is here}}
+template <typename, typename>
+int c;
+// since-cxx20-error at -1 {{redefinition of 'c' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:44 {{previous definition is here}}
+template <typename T>
+int c<T, int>;
+// since-cxx20-error at -1 {{redefinition of 'c' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:44 {{previous definition is here}}
+// since-cxx20-error at -3 {{expected ';' after top level declarator}}
+template <typename>
+using c = int;
+// since-cxx20-error at -1 {{redefinition of 'c' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:44 {{previous definition is here}}
+template <typename>
+concept c = true;
+// since-cxx20-error at -1 {{redefinition of 'c' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:44 {{previous definition is here}}
+
+
+// namespace d {};
+
+int d;
+// since-cxx20-error at -1 {{redefinition of 'd' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:45 {{previous definition is here}}
+void d();
+// since-cxx20-error at -1 {{redefinition of 'd' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:45 {{previous definition is here}}
+enum Ed {
+  d
+  // since-cxx20-error at -1 {{redefinition of 'd'}}
+  //   since-cxx20-note at cwg1884_A.cppm:45 {{previous definition is here}}
+};
+struct d;
+// since-cxx20-error at -1 {{redefinition of 'd' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:45 {{previous definition is here}}
+class d;
+// since-cxx20-error at -1 {{redefinition of 'd' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:45 {{previous definition is here}}
+template <typename>
+class d;
+// since-cxx20-error at -1 {{redefinition of 'd' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:45 {{previous definition is here}}
+template <typename>
+void d(int);
+// since-cxx20-error at -1 {{redefinition of 'd' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:45 {{previous definition is here}}
+template <typename, typename>
+int d;
+// since-cxx20-error at -1 {{redefinition of 'd' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:45 {{previous definition is here}}
+template <typename T>
+int d<T, int>;
+// since-cxx20-error at -1 {{redefinition of 'd' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:45 {{previous definition is here}}
+// since-cxx20-error at -3 {{expected ';' after top level declarator}}
+template <typename>
+using d = int;
+// since-cxx20-error at -1 {{redefinition of 'd' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:45 {{previous definition is here}}
+template <typename>
+concept d = true;
+// since-cxx20-error at -1 {{redefinition of 'd' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:45 {{previous definition is here}}
+
+
+// struct e;
+
+int e; // #cwg1884-int-e
+// @-1 OK, types and variables do not correspond
+void e();
+// since-cxx20-error at -1 {{redefinition of 'e' as different kind of symbol}}
+//   since-cxx20-note@#cwg1884-int-e {{previous definition is here}}
+enum Ee {
+  e
+  // since-cxx20-error at -1 {{redefinition of 'e'}}
+  //   since-cxx20-note@#cwg1884-int-e {{previous definition is here}}
+};
+namespace e {} // #cwg1884-namespace-e
+// since-cxx20-error at -1 {{redefinition of 'e' as different kind of symbol}}
+//   since-cxx20-note@#cwg1884-int-e {{previous definition is here}}
+class e;
+// since-cxx20-error at -1 {{declaration of 'e' in the global module follows declaration in module cwg1884_A}}
+//   since-cxx20-note at cwg1884_A.cppm:46 {{previous declaration is here}}
+template <typename>
+class e;
+// since-cxx20-error at -1 {{redefinition of 'e' as different kind of symbol}}
+//   since-cxx20-note@#cwg1884-int-e {{previous definition is here}}
+template <typename>
+void e(int);
+// since-cxx20-error at -1 {{redefinition of 'e' as different kind of symbol}}
+//   since-cxx20-note@#cwg1884-int-e {{previous definition is here}}
+template <typename, typename>
+int e;
+// since-cxx20-error at -1 {{redefinition of 'e' as different kind of symbol}}
+//   since-cxx20-note@#cwg1884-int-e {{previous definition is here}}
+template <typename T>
+int e<T, int>;
+// since-cxx20-error at -1 {{redefinition of 'e' as different kind of symbol}}
+//   since-cxx20-note@#cwg1884-int-e {{previous definition is here}}
+// since-cxx20-error at -3 {{expected ';' after top level declarator}}
+template <typename>
+using e = int;
+// since-cxx20-error at -1 {{redefinition of 'e' as different kind of symbol}}
+//   since-cxx20-note@#cwg1884-int-e {{previous definition is here}}
+template <typename>
+concept e = true;
+// since-cxx20-error at -1 {{redefinition of 'e' as different kind of symbol}}
+//   since-cxx20-note@#cwg1884-int-e {{previous definition is here}}
+
+
+// class f;
+
+int f; // #cwg1884-int-f
+// @-1 OK, types and variables do not correspond
+void f();
+// since-cxx20-error at -1 {{redefinition of 'f' as different kind of symbol}}
+//   since-cxx20-note@#cwg1884-int-f {{previous definition is here}}
+enum Ef {
+  f
+  // since-cxx20-error at -1 {{redefinition of 'f'}}
+  //   since-cxx20-note@#cwg1884-int-f {{previous definition is here}}
+};
+namespace f {} // #cwg1884-namespace-f
+// since-cxx20-error at -1 {{redefinition of 'f' as different kind of symbol}}
+//   since-cxx20-note@#cwg1884-int-f {{previous definition is here}}
+struct f;
+// since-cxx20-error at -1 {{declaration of 'f' in the global module follows declaration in module cwg1884_A}}
+//   since-cxx20-note at cwg1884_A.cppm:47 {{previous declaration is here}}
+template <typename>
+class f;
+// since-cxx20-error at -1 {{redefinition of 'f' as different kind of symbol}}
+//   since-cxx20-note@#cwg1884-int-f {{previous definition is here}}
+template <typename>
+void f(int);
+// since-cxx20-error at -1 {{redefinition of 'f' as different kind of symbol}}
+//   since-cxx20-note@#cwg1884-int-f {{previous definition is here}}
+template <typename, typename>
+int f;
+// since-cxx20-error at -1 {{redefinition of 'f' as different kind of symbol}}
+//   since-cxx20-note@#cwg1884-int-f {{previous definition is here}}
+template <typename T>
+int f<T, int>;
+// since-cxx20-error at -1 {{redefinition of 'f' as different kind of symbol}}
+//   since-cxx20-note@#cwg1884-int-f {{previous definition is here}}
+// since-cxx20-error at -3 {{expected ';' after top level declarator}}
+template <typename>
+using f = int;
+// since-cxx20-error at -1 {{redefinition of 'f' as different kind of symbol}}
+//   since-cxx20-note@#cwg1884-int-f {{previous definition is here}}
+template <typename>
+concept f = true;
+// since-cxx20-error at -1 {{redefinition of 'f' as different kind of symbol}}
+//   since-cxx20-note@#cwg1884-int-f {{previous definition is here}}
+
+
+// template <typename>
+// class g;
+
+int g;
+// since-cxx20-error at -1 {{redefinition of 'g' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:49 {{previous definition is here}}
+void g();
+// since-cxx20-error at -1 {{redefinition of 'g' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:49 {{previous definition is here}}
+enum Eg {
+  g
+  // since-cxx20-error at -1 {{redefinition of 'g'}}
+  //   since-cxx20-note at cwg1884_A.cppm:49 {{previous definition is here}}
+};
+namespace g {}
+// since-cxx20-error at -1 {{redefinition of 'g' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:49 {{previous definition is here}}
+struct g;
+// since-cxx20-error at -1 {{redefinition of 'g' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:49 {{previous definition is here}}
+class g;
+// since-cxx20-error at -1 {{redefinition of 'g' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:49 {{previous definition is here}}
+template <typename>
+void g(int);
+// since-cxx20-error at -1 {{redefinition of 'g' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:49 {{previous definition is here}}
+template <typename, typename>
+int g;
+// since-cxx20-error at -1 {{redefinition of 'g' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:49 {{previous definition is here}}
+template <typename T>
+int g<T, int>;
+// since-cxx20-error at -1 {{no variable template matches partial specialization}}
+template <typename>
+using g = int;
+// since-cxx20-error at -1 {{redefinition of 'g' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:49 {{previous definition is here}}
+template <typename>
+concept g = true;
+// since-cxx20-error at -1 {{redefinition of 'g' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:49 {{previous definition is here}}
+
+
+// template <typename>
+// void h(int);
+
+int h;
+// since-cxx20-error at -1 {{redefinition of 'h' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:51 {{previous definition is here}}
+void h(); // #cwg1884-function-f
+// @-1 OK, a non-corresponding overload
+enum Eh {
+  h
+  // FIXME-since-cxx20-error at -1 {{redefinition of 'h'}}
+  //   FIXME-since-cxx20-note at cwg1884_A.cppm:51 {{previous definition is here}}
+};
+namespace h {} // #cwg1884-namespace-h
+// FIXME-since-cxx20-error at -1 {{redefinition of 'h' as different kind of symbol}}
+//   FIXME-since-cxx20-note at cwg1884_A.cppm:51 {{previous definition is here}}
+struct h;
+// since-cxx20-error at -1 {{redefinition of 'h' as different kind of symbol}}
+//   since-cxx20-note@#cwg1884-namespace-h {{previous definition is here}}
+class h;
+// since-cxx20-error at -1 {{redefinition of 'h' as different kind of symbol}}
+//   since-cxx20-note@#cwg1884-namespace-h {{previous definition is here}}
+template <typename>
+class h;
+// FIXME-since-cxx20-error at -1 {{redefinition of 'h' as different kind of symbol}}
+//   FIXME-since-cxx20-note at cwg1884_A.cppm:51 {{previous definition is here}}
+template <typename, typename>
+int h;
+// since-cxx20-error at -1 {{redefinition of 'h' as different kind of symbol}}
+//   since-cxx20-note@#cwg1884-namespace-h {{previous definition is here}}
+template <typename T>
+int h<T, int>;
+// since-cxx20-error at -1 {{no variable template matches specialization; did you mean to use 'h' as function template instead?}}
+template <typename>
+using h = int;
+// since-cxx20-error at -1 {{redefinition of 'h' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:51 {{previous definition is here}}
+template <typename>
+concept h = true;
+// since-cxx20-error at -1 {{redefinition of 'h' as different kind of symbol}}
+//   since-cxx20-note@#cwg1884-function-f {{previous definition is here}}
+
+
+// template <typename, typename>
+// int i;
+
+int i;
+// since-cxx20-error at -1 {{redefinition of 'i' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:53 {{previous definition is here}}
+void i();
+// since-cxx20-error at -1 {{redefinition of 'i' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:53 {{previous definition is here}}
+enum Ei {
+  i
+  // since-cxx20-error at -1 {{redefinition of 'i'}}
+  //   since-cxx20-note at cwg1884_A.cppm:53 {{previous definition is here}}
+};
+namespace i {}
+// since-cxx20-error at -1 {{redefinition of 'i' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:53 {{previous definition is here}}
+struct i;
+// since-cxx20-error at -1 {{redefinition of 'i' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:53 {{previous definition is here}}
+class i;
+// since-cxx20-error at -1 {{redefinition of 'i' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:53 {{previous definition is here}}
+template <typename>
+class i;
+// since-cxx20-error at -1 {{redefinition of 'i' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:53 {{previous definition is here}}
+template <typename>
+void i(int);
+// since-cxx20-error at -1 {{redefinition of 'i' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:53 {{previous definition is here}}
+template <typename T>
+int i<T, int>; // OK, partial specialization
+template <typename>
+using i = int;
+// since-cxx20-error at -1 {{redefinition of 'i' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:53 {{previous definition is here}}
+template <typename>
+concept i = true;
+// since-cxx20-error at -1 {{redefinition of 'i' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:53 {{previous definition is here}}
+
+
+// template <typename>
+// using j = int;
+
+int j;
+// since-cxx20-error at -1 {{redefinition of 'j' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:55 {{previous definition is here}}
+void j();
+// since-cxx20-error at -1 {{redefinition of 'j' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:55 {{previous definition is here}}
+enum Ej {
+  j
+  // since-cxx20-error at -1 {{redefinition of 'j'}}
+  //   since-cxx20-note at cwg1884_A.cppm:55 {{previous definition is here}}
+};
+namespace j {}
+// since-cxx20-error at -1 {{redefinition of 'j' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:55 {{previous definition is here}}
+struct j;
+// since-cxx20-error at -1 {{redefinition of 'j' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:55 {{previous definition is here}}
+class j;
+// since-cxx20-error at -1 {{redefinition of 'j' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:55 {{previous definition is here}}
+template <typename>
+class j;
+// since-cxx20-error at -1 {{redefinition of 'j' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:55 {{previous definition is here}}
+template <typename>
+void j(int);
+// since-cxx20-error at -1 {{redefinition of 'j' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:55 {{previous definition is here}}
+template <typename, typename>
+int j;
+// since-cxx20-error at -1 {{redefinition of 'j' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:55 {{previous definition is here}}
+template <typename T>
+int j<T, int>;
+// since-cxx20-error at -1 {{no variable template matches partial specialization}}
+template <typename>
+concept j = true;
+// since-cxx20-error at -1 {{redefinition of 'j' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:55 {{previous definition is here}}
+
+
+// template <typename>
+// concept k = true;
+
+int k;
+// since-cxx20-error at -1 {{redefinition of 'k' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:57 {{previous definition is here}}
+void k();
+// since-cxx20-error at -1 {{redefinition of 'k' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:57 {{previous definition is here}}
+enum Ek {
+  k
+  // since-cxx20-error at -1 {{redefinition of 'k'}}
+  //   since-cxx20-note at cwg1884_A.cppm:57 {{previous definition is here}}
+};
+namespace k {}
+// since-cxx20-error at -1 {{redefinition of 'k' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:57 {{previous definition is here}}
+struct k;
+// since-cxx20-error at -1 {{redefinition of 'k' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:57 {{previous definition is here}}
+class k;
+// since-cxx20-error at -1 {{redefinition of 'k' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:57 {{previous definition is here}}
+template <typename>
+class k;
+// since-cxx20-error at -1 {{redefinition of 'k' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:57 {{previous definition is here}}
+template <typename>
+void k(int);
+// since-cxx20-error at -1 {{redefinition of 'k' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:57 {{previous definition is here}}
+template <typename, typename>
+int k;
+// since-cxx20-error at -1 {{redefinition of 'k' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:57 {{previous definition is here}}
+template <typename T>
+int k<T, int>;
+// since-cxx20-error at -1 {{no variable template matches partial specialization}}
+template <typename>
+using k = int;
+// since-cxx20-error at -1 {{redefinition of 'k' as different kind of symbol}}
+//   since-cxx20-note at cwg1884_A.cppm:57 {{previous definition is here}}
diff --git a/clang/test/CXX/drs/cwg18xx.cpp b/clang/test/CXX/drs/cwg18xx.cpp
index b059492637bd5c..0fd2cd6b2d870c 100644
--- a/clang/test/CXX/drs/cwg18xx.cpp
+++ b/clang/test/CXX/drs/cwg18xx.cpp
@@ -547,6 +547,8 @@ namespace cwg1881 { // cwg1881: 7
   static_assert(!__is_standard_layout(D), "");
 }
 
+// cwg1884 is in cwg1884.cpp
+
 namespace cwg1890 { // cwg1890: no drafting 2018-06-04
 // FIXME: current consensus for CWG2335 is that the examples are well-formed.
 namespace ex1 {
diff --git a/clang/test/CXX/drs/cwg279.cpp b/clang/test/CXX/drs/cwg279.cpp
new file mode 100644
index 00000000000000..3f3782b79ebff8
--- /dev/null
+++ b/clang/test/CXX/drs/cwg279.cpp
@@ -0,0 +1,42 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: split-file --leading-lines %s %t
+// RUN: %clang_cc1 -std=c++20 -pedantic-errors -fexceptions -fcxx-exceptions %t/cwg279_A.cppm -triple x86_64-unknown-unknown -emit-module-interface -o %t/cwg279_A.pcm
+// RUN: %clang_cc1 -std=c++20 -verify=since-cxx20 -pedantic-errors -fexceptions -fcxx-exceptions -triple x86_64-unknown-unknown %t/cwg279.cpp -fmodule-file=cwg279_A=%t/cwg279_A.pcm
+// RUN: %clang_cc1 -std=c++23 -pedantic-errors -fexceptions -fcxx-exceptions %t/cwg279_A.cppm -triple x86_64-unknown-unknown -emit-module-interface -o %t/cwg279_A.pcm
+// RUN: %clang_cc1 -std=c++23 -verify=since-cxx20 -pedantic-errors -fexceptions -fcxx-exceptions -triple x86_64-unknown-unknown %t/cwg279.cpp -fmodule-file=cwg279_A=%t/cwg279_A.pcm
+// RUN: %clang_cc1 -std=c++2c -pedantic-errors -fexceptions -fcxx-exceptions %t/cwg279_A.cppm -triple x86_64-unknown-unknown -emit-module-interface -o %t/cwg279_A.pcm
+// RUN: %clang_cc1 -std=c++2c -verify=since-cxx20 -pedantic-errors -fexceptions -fcxx-exceptions -triple x86_64-unknown-unknown %t/cwg279.cpp -fmodule-file=cwg279_A=%t/cwg279_A.pcm
+
+// cwg279: no
+
+//--- cwg279_A.cppm
+export module cwg279_A;
+
+export {
+struct S; // #cwg279-S
+extern S *q; // #cwg279-q
+
+struct S2 {}; // #cwg279-S2
+extern S2 *q2; // #cwg279-q2
+} // export
+
+//--- cwg279.cpp
+import cwg279_A;
+
+// FIXME: We should use markers instead. They are less fragile,
+//        but -verify doesn't support them across modules yet.
+// FIXME: This is well-formed. Previous "definition" is actually just a declaration.
+typedef struct {} S;
+// since-cxx20-error at -1 {{typedef redefinition with different types ('struct S' vs 'S')}}
+//   since-cxx20-note at cwg279_A.cppm:17 {{previous definition is here}}
+extern S *q;
+// since-cxx20-error at -1 {{declaration of 'q' in the global module follows declaration in module cwg279_A}}
+//   since-cxx20-note at cwg279_A.cppm:18 {{previous declaration is here}}
+
+typedef struct {} S2;
+// since-cxx20-error at -1 {{typedef redefinition with different types ('struct S2' vs 'S2')}}
+//   since-cxx20-note at cwg279_A.cppm:20 {{previous definition is here}}
+extern S2 *q2;
+// since-cxx20-error at -1 {{declaration of 'q2' in the global module follows declaration in module cwg279_A}}
+//   since-cxx20-note at cwg279_A.cppm:21 {{previous declaration is here}}
diff --git a/clang/test/CXX/drs/cwg2xx.cpp b/clang/test/CXX/drs/cwg2xx.cpp
index 926cb19596026b..ec37b420880e28 100644
--- a/clang/test/CXX/drs/cwg2xx.cpp
+++ b/clang/test/CXX/drs/cwg2xx.cpp
@@ -1032,6 +1032,8 @@ namespace cwg277 { // cwg277: 3.1
   static_assert(__enable_constant_folding(!intp()), "");
 }
 
+// cwg279 is in cwg279.cpp
+
 namespace cwg280 { // cwg280: 2.9
   typedef void f0();
   typedef void f1(int);
diff --git a/clang/test/CXX/drs/cwg3xx.cpp b/clang/test/CXX/drs/cwg3xx.cpp
index f20054c3701b1c..10c8d86ed16a0d 100644
--- a/clang/test/CXX/drs/cwg3xx.cpp
+++ b/clang/test/CXX/drs/cwg3xx.cpp
@@ -637,6 +637,8 @@ namespace cwg337 { // cwg337: yes
   struct B { virtual ~B() = 0; };
 }
 
+// cwg338: dup 1884
+
 namespace cwg339 { // cwg339: 2.8
   template <int I> struct A { static const int value = I; };
 
diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html
index 6640ed477a241e..186f7cc0ace546 100755
--- a/clang/www/cxx_dr_status.html
+++ b/clang/www/cxx_dr_status.html
@@ -1721,7 +1721,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
     <td><a href="https://cplusplus.github.io/CWG/issues/279.html">279</a></td>
     <td>CD6</td>
     <td>Correspondence of "names for linkage purposes"</td>
-    <td class="unknown" align="center">Unknown</td>
+    <td class="none" align="center">No</td>
   </tr>
   <tr id="280">
     <td><a href="https://cplusplus.github.io/CWG/issues/280.html">280</a></td>
@@ -2075,7 +2075,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
     <td><a href="https://cplusplus.github.io/CWG/issues/338.html">338</a></td>
     <td>CD6</td>
     <td>Enumerator name with linkage used as class name in other translation unit</td>
-    <td class="unknown" align="center">Unknown</td>
+    <td class="partial" align="center">Duplicate of <a href="#1884">1884</a></td>
   </tr>
   <tr id="339">
     <td><a href="https://cplusplus.github.io/CWG/issues/339.html">339</a></td>
@@ -11131,7 +11131,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
     <td><a href="https://cplusplus.github.io/CWG/issues/1884.html">1884</a></td>
     <td>CD6</td>
     <td>Unclear requirements for same-named external-linkage entities</td>
-    <td class="unknown" align="center">Unknown</td>
+    <td class="partial" align="center">Partial</td>
   </tr>
   <tr id="1885">
     <td><a href="https://cplusplus.github.io/CWG/issues/1885.html">1885</a></td>



More information about the cfe-commits mailing list