diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -15539,6 +15539,21 @@ // shouldn't be diagnosing. LookupName(Previous, S); + // Under MSVC, the 'enum' specifier can be used for typedef'd enums. + // Note that lookup only fails in C, not C++, so this if condition + // is only used for C code. + if (getLangOpts().MSVCCompat && Kind == TTK_Enum && Previous.empty() && + TUK == TUK_Reference) { + LookupResult TypedefEnumLookup(*this, Name, NameLoc, LookupOrdinaryName, + Redecl); + LookupName(TypedefEnumLookup, S); + + if (auto *TD = TypedefEnumLookup.getAsSingle()) + if (auto *TT = TD->getUnderlyingType()->getAs()) + if (auto *ED = dyn_cast_or_null(TT->getDecl())) + Previous.addDecl(ED); + } + // When declaring or defining a tag, ignore ambiguities introduced // by types using'ed into this scope. if (Previous.isAmbiguous() && @@ -15721,9 +15736,12 @@ if (TypedefNameDecl *TD = dyn_cast(PrevDecl)) { if (const TagType *TT = TD->getUnderlyingType()->getAs()) { TagDecl *Tag = TT->getDecl(); - if (Tag->getDeclName() == Name && - Tag->getDeclContext()->getRedeclContext() - ->Equals(TD->getDeclContext()->getRedeclContext())) { + bool AllowLookupUsingTypedefName = getLangOpts().MSVCCompat && + TUK == TUK_Reference && + Kind == TTK_Enum; + if ((Tag->getDeclName() == Name || AllowLookupUsingTypedefName) && + Tag->getDeclContext()->getRedeclContext()->Equals( + TD->getDeclContext()->getRedeclContext())) { PrevDecl = Tag; Previous.clear(); Previous.addDecl(Tag); diff --git a/clang/test/Sema/enum-typedef-msvc.c b/clang/test/Sema/enum-typedef-msvc.c new file mode 100644 --- /dev/null +++ b/clang/test/Sema/enum-typedef-msvc.c @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fsyntax-only -verify -fms-compatibility -DUSE_MSVC_COMPAT %s + +typedef enum FooEnum { + A +} Foo; + +void func() { +#ifdef USE_MSVC_COMPAT + enum Foo foo; // expected-no-diagnostics +#else + enum Foo foo; // expected-error {{variable has incomplete type 'enum Foo'}} // expected-note {{forward declaration of 'enum Foo'}} +#endif + (void)foo; +} + +#ifdef USE_MSVC_COMPAT +enum Foo foo2; // expected-no-diagnostics +#else +enum Foo foo2; // expected-error {{tentative definition has type 'enum Foo' that is never completed}} + // expected-note@-1 {{forward declaration of 'enum Foo'}} +#endif diff --git a/clang/test/Sema/enum-typedef-msvc.cpp b/clang/test/Sema/enum-typedef-msvc.cpp new file mode 100644 --- /dev/null +++ b/clang/test/Sema/enum-typedef-msvc.cpp @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -fms-compatibility %s + +typedef enum FooEnum { + A, +} Foo; + +class AMyInterface { + virtual void MyFunc(enum Foo *param) = 0; +}; + +class MyImpl : public AMyInterface { + virtual void MyFunc(enum Foo *param) override {} +}; + +enum Foo myEnum; + +// expected-no-diagnostics