shivanshu3 updated this revision to Diff 305971. shivanshu3 added a reviewer: rsmith. shivanshu3 added a comment.
Addressing some of rsmith's comments: - Add a test case where an enum variable is declared in the same scope as the enum definition - Fix a style issue with parentheses - Simplify the if condition for the C case - The C++ case should only apply for TUK_Reference Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D91659/new/ https://reviews.llvm.org/D91659 Files: clang/lib/Sema/SemaDecl.cpp clang/test/Sema/enum-typedef-msvc.c clang/test/Sema/enum-typedef-msvc.cpp Index: clang/test/Sema/enum-typedef-msvc.cpp =================================================================== --- /dev/null +++ clang/test/Sema/enum-typedef-msvc.cpp @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -fms-compatibility %s + +typedef enum { + First, + Second +} MyEnum; + +class AMyInterface { + virtual void MyFunc(enum MyEnum *param) = 0; +}; + +class MyImpl : public AMyInterface { + virtual void MyFunc(enum MyEnum *param) override {} +}; + +enum MyEnum myEnum; + +// expected-no-diagnostics Index: clang/test/Sema/enum-typedef-msvc.c =================================================================== --- /dev/null +++ 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 { + 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 Index: clang/lib/Sema/SemaDecl.cpp =================================================================== --- clang/lib/Sema/SemaDecl.cpp +++ 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<TypedefNameDecl>()) + if (auto *ED = dyn_cast_or_null<EnumDecl>( + TD->getAnonDeclWithTypedefName(true))) + 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<TypedefNameDecl>(PrevDecl)) { if (const TagType *TT = TD->getUnderlyingType()->getAs<TagType>()) { TagDecl *Tag = TT->getDecl(); - if (Tag->getDeclName() == Name && - Tag->getDeclContext()->getRedeclContext() - ->Equals(TD->getDeclContext()->getRedeclContext())) { + bool AnonymousEnumEligible = + getLangOpts().MSVCCompat && TUK == TUK_Reference && + Kind == TTK_Enum && Tag->getDeclName().isEmpty(); + if ((Tag->getDeclName() == Name || AnonymousEnumEligible) && + Tag->getDeclContext()->getRedeclContext()->Equals( + TD->getDeclContext()->getRedeclContext())) { PrevDecl = Tag; Previous.clear(); Previous.addDecl(Tag);
Index: clang/test/Sema/enum-typedef-msvc.cpp =================================================================== --- /dev/null +++ clang/test/Sema/enum-typedef-msvc.cpp @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -fms-compatibility %s + +typedef enum { + First, + Second +} MyEnum; + +class AMyInterface { + virtual void MyFunc(enum MyEnum *param) = 0; +}; + +class MyImpl : public AMyInterface { + virtual void MyFunc(enum MyEnum *param) override {} +}; + +enum MyEnum myEnum; + +// expected-no-diagnostics Index: clang/test/Sema/enum-typedef-msvc.c =================================================================== --- /dev/null +++ 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 { + 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 Index: clang/lib/Sema/SemaDecl.cpp =================================================================== --- clang/lib/Sema/SemaDecl.cpp +++ 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<TypedefNameDecl>()) + if (auto *ED = dyn_cast_or_null<EnumDecl>( + TD->getAnonDeclWithTypedefName(true))) + 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<TypedefNameDecl>(PrevDecl)) { if (const TagType *TT = TD->getUnderlyingType()->getAs<TagType>()) { TagDecl *Tag = TT->getDecl(); - if (Tag->getDeclName() == Name && - Tag->getDeclContext()->getRedeclContext() - ->Equals(TD->getDeclContext()->getRedeclContext())) { + bool AnonymousEnumEligible = + getLangOpts().MSVCCompat && TUK == TUK_Reference && + Kind == TTK_Enum && Tag->getDeclName().isEmpty(); + if ((Tag->getDeclName() == Name || AnonymousEnumEligible) && + Tag->getDeclContext()->getRedeclContext()->Equals( + TD->getDeclContext()->getRedeclContext())) { PrevDecl = Tag; Previous.clear(); Previous.addDecl(Tag);
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits