} 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))
--- /dev/null
+// 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}}
+};