Re-land "[MS] Fix assert handling enum forward decls in hasVisibleDefinition"
authorReid Kleckner <rnk@google.com>
Mon, 20 Apr 2020 19:50:20 +0000 (12:50 -0700)
committerReid Kleckner <rnk@google.com>
Thu, 23 Apr 2020 23:22:01 +0000 (16:22 -0700)
This reverts commit 9b2ab41037f45ad92ab4e850591093ffc45d3e10 and
reinstates e62dc1f6252c1dcdcc2a64e8e3b07a32412e9d89 with changes.

This fix is speculative, since I don't have access to a crashing test
case for the old code, and fixing the crash bug on Windows when C++20 is
enabled seems more important than running it down.

clang/lib/Sema/SemaType.cpp
clang/test/Modules/Inputs/ms-enums/A.h [new file with mode: 0644]
clang/test/Modules/Inputs/ms-enums/B.h [new file with mode: 0644]
clang/test/Modules/Inputs/ms-enums/module.map [new file with mode: 0644]
clang/test/Modules/ms-enums.cpp [new file with mode: 0644]

index 8d92502..a96e1c1 100644 (file)
@@ -8120,10 +8120,12 @@ bool Sema::hasVisibleDefinition(NamedDecl *D, NamedDecl **Suggested,
   } else if (auto *ED = dyn_cast<EnumDecl>(D)) {
     if (auto *Pattern = ED->getTemplateInstantiationPattern())
       ED = Pattern;
-    if (OnlyNeedComplete && ED->isFixed()) {
-      // If the enum has a fixed underlying type, and we're only looking for a
-      // complete type (not a definition), any visible declaration of it will
-      // do.
+    if (OnlyNeedComplete && (ED->isFixed() || getLangOpts().MSVCCompat)) {
+      // If the enum has a fixed underlying type, it may have been forward
+      // declared. In -fms-compatibility, `enum Foo;` will also forward declare
+      // the enum and assign it the underlying type of `int`. Since we're only
+      // looking for a complete type (not a definition), any visible declaration
+      // of it will do.
       *Suggested = nullptr;
       for (auto *Redecl : ED->redecls()) {
         if (isVisible(Redecl))
diff --git a/clang/test/Modules/Inputs/ms-enums/A.h b/clang/test/Modules/Inputs/ms-enums/A.h
new file mode 100644 (file)
index 0000000..1684452
--- /dev/null
@@ -0,0 +1 @@
+enum fwd_enum;
diff --git a/clang/test/Modules/Inputs/ms-enums/B.h b/clang/test/Modules/Inputs/ms-enums/B.h
new file mode 100644 (file)
index 0000000..7a13ba4
--- /dev/null
@@ -0,0 +1 @@
+#include "A.h"
diff --git a/clang/test/Modules/Inputs/ms-enums/module.map b/clang/test/Modules/Inputs/ms-enums/module.map
new file mode 100644 (file)
index 0000000..d9aed01
--- /dev/null
@@ -0,0 +1,2 @@
+module A { header "A.h" }
+module B { header "B.h" }
diff --git a/clang/test/Modules/ms-enums.cpp b/clang/test/Modules/ms-enums.cpp
new file mode 100644 (file)
index 0000000..b3a377c
--- /dev/null
@@ -0,0 +1,12 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -triple x86_64-windows-msvc -fms-extensions -fms-compatibility -x c++ -std=c++20 -fmodules-cache-path=%t -fmodules -fimplicit-module-maps -I %S/Inputs/ms-enums %s -verify -fno-modules-error-recovery
+
+#include "B.h"
+// expected-note@A.h:1 {{previous declaration is here}}
+// expected-note@A.h:1 2 {{previous definition is here}}
+
+fwd_enum gv_enum; // expected-error {{must be imported}}
+
+struct Foo {
+  enum fwd_enum enum_field; // expected-error 2 {{must be imported}}
+};