[ASTImporter] Added visibility check for scoped enums.
authorBalázs Kéri <1.int32@gmail.com>
Mon, 17 Feb 2020 13:25:16 +0000 (14:25 +0100)
committerBalázs Kéri <1.int32@gmail.com>
Mon, 17 Feb 2020 13:34:13 +0000 (14:34 +0100)
Summary:
ASTImporter makes now difference between C++11 scoped enums with same
name in different translation units if these are not visible outside.
Enum declarations are linked into decl chain correctly.

Reviewers: martong, a.sidorin, shafik, a_sidorin, teemperor

Reviewed By: shafik, a_sidorin

Subscribers: rnkovacs, dkrupp, Szelethus, gamesh411, teemperor, cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D74554

clang/lib/AST/ASTImporter.cpp
clang/unittests/AST/ASTImporterGenericRedeclTest.cpp
clang/unittests/AST/ASTImporterODRStrategiesTest.cpp
clang/unittests/AST/ASTImporterVisibilityTest.cpp

index 49058ce..8710ef0 100644 (file)
@@ -2578,6 +2578,7 @@ ExpectedDecl ASTNodeImporter::VisitEnumDecl(EnumDecl *D) {
     IDNS |= Decl::IDNS_Ordinary;
 
   // We may already have an enum of the same name; try to find and match it.
+  EnumDecl *PrevDecl = nullptr;
   if (!DC->isFunctionOrMethod() && SearchName) {
     SmallVector<NamedDecl *, 4> ConflictingDecls;
     auto FoundDecls =
@@ -2594,8 +2595,13 @@ ExpectedDecl ASTNodeImporter::VisitEnumDecl(EnumDecl *D) {
       if (auto *FoundEnum = dyn_cast<EnumDecl>(FoundDecl)) {
         if (!hasSameVisibilityContext(FoundEnum, D))
           continue;
-        if (IsStructuralMatch(D, FoundEnum))
-          return Importer.MapImported(D, FoundEnum);
+        if (IsStructuralMatch(D, FoundEnum)) {
+          EnumDecl *FoundDef = FoundEnum->getDefinition();
+          if (D->isThisDeclarationADefinition() && FoundDef)
+            return Importer.MapImported(D, FoundDef);
+          PrevDecl = FoundEnum->getMostRecentDecl();
+          break;
+        }
         ConflictingDecls.push_back(FoundDecl);
       }
     }
@@ -2623,7 +2629,7 @@ ExpectedDecl ASTNodeImporter::VisitEnumDecl(EnumDecl *D) {
   EnumDecl *D2;
   if (GetImportedOrCreateDecl(
           D2, D, Importer.getToContext(), DC, ToBeginLoc,
-          Loc, Name.getAsIdentifierInfo(), nullptr, D->isScoped(),
+          Loc, Name.getAsIdentifierInfo(), PrevDecl, D->isScoped(),
           D->isScopedUsingClassTag(), D->isFixed()))
     return D2;
 
index 0f994c1..e0c5e94 100644 (file)
@@ -35,6 +35,15 @@ struct Class {
   }
 };
 
+struct EnumClass {
+  using DeclTy = EnumDecl;
+  static constexpr auto *Prototype = "enum class X;";
+  static constexpr auto *Definition = "enum class X {};";
+  BindableMatcher<Decl> getPattern() {
+    return enumDecl(hasName("X"), unless(isImplicit()));
+  }
+};
+
 struct Variable {
   using DeclTy = VarDecl;
   static constexpr auto *Prototype = "extern int X;";
@@ -407,6 +416,9 @@ ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(
     RedeclChain, Class, ,
     PrototypeShouldBeImportedAsAPrototypeWhenThereIsNoDefinition)
 ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(
+    RedeclChain, EnumClass, ,
+    PrototypeShouldBeImportedAsAPrototypeWhenThereIsNoDefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(
     RedeclChain, Variable, ,
     PrototypeShouldBeImportedAsAPrototypeWhenThereIsNoDefinition)
 ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(
@@ -426,6 +438,8 @@ ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Function, ,
                                         DefinitionShouldBeImportedAsADefinition)
 ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Class, ,
                                         DefinitionShouldBeImportedAsADefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, EnumClass, ,
+                                        DefinitionShouldBeImportedAsADefinition)
 ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, ,
                                         DefinitionShouldBeImportedAsADefinition)
 ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
@@ -441,6 +455,8 @@ ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Function, ,
                                         ImportPrototypeAfterImportedPrototype)
 ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Class, ,
                                         ImportPrototypeAfterImportedPrototype)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, EnumClass, ,
+                                        ImportPrototypeAfterImportedPrototype)
 ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, ,
                                         ImportPrototypeAfterImportedPrototype)
 ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
@@ -456,6 +472,8 @@ ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Function, ,
                                         ImportDefinitionAfterImportedPrototype)
 ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Class, ,
                                         ImportDefinitionAfterImportedPrototype)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, EnumClass, ,
+                                        ImportDefinitionAfterImportedPrototype)
 ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, ,
                                         ImportDefinitionAfterImportedPrototype)
 ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
@@ -471,6 +489,8 @@ ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Function, ,
                                         ImportPrototypeAfterImportedDefinition)
 ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Class, ,
                                         ImportPrototypeAfterImportedDefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, EnumClass, ,
+                                        ImportPrototypeAfterImportedDefinition)
 ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, ,
                                         ImportPrototypeAfterImportedDefinition)
 ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
@@ -485,6 +505,8 @@ ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, ClassTemplateSpec, ,
 ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Function, ,
                                         ImportPrototypes)
 ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Class, , ImportPrototypes)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, EnumClass, ,
+                                        ImportPrototypes)
 ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, ,
                                         ImportPrototypes)
 ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
@@ -499,6 +521,8 @@ ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplateSpec, ,
 ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Function, ,
                                         ImportDefinitions)
 ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Class, , ImportDefinitions)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, EnumClass, ,
+                                        ImportDefinitions)
 ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, ,
                                         ImportDefinitions)
 ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
@@ -514,6 +538,8 @@ ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Function, ,
                                         ImportDefinitionThenPrototype)
 ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Class, ,
                                         ImportDefinitionThenPrototype)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, EnumClass, ,
+                                        ImportDefinitionThenPrototype)
 ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, ,
                                         ImportDefinitionThenPrototype)
 ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
@@ -529,6 +555,8 @@ ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Function, ,
                                         ImportPrototypeThenDefinition)
 ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Class, ,
                                         ImportPrototypeThenDefinition)
+ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, EnumClass, ,
+                                        ImportPrototypeThenDefinition)
 ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, Variable, ,
                                         ImportPrototypeThenDefinition)
 ASTIMPORTER_INSTANTIATE_TYPED_TEST_CASE(RedeclChain, FunctionTemplate, ,
@@ -562,6 +590,8 @@ INSTANTIATE_TEST_CASE_P(ParameterizedTests, RedeclChainFunction,
                         DefaultTestValuesForRunOptions, );
 INSTANTIATE_TEST_CASE_P(ParameterizedTests, RedeclChainClass,
                         DefaultTestValuesForRunOptions, );
+INSTANTIATE_TEST_CASE_P(ParameterizedTests, RedeclChainEnumClass,
+                        DefaultTestValuesForRunOptions, );
 INSTANTIATE_TEST_CASE_P(ParameterizedTests, RedeclChainVariable,
                         DefaultTestValuesForRunOptions, );
 INSTANTIATE_TEST_CASE_P(ParameterizedTests, RedeclChainFunctionTemplate,
index 6a2aa2b..2bd62e2 100644 (file)
@@ -64,6 +64,14 @@ struct Enum {
   Language getLang() { return Lang_CXX; }
 };
 
+struct EnumClass {
+  using DeclTy = EnumDecl;
+  static constexpr auto *Definition = "enum class X { a, b };";
+  static constexpr auto *ConflictingDefinition = "enum class X { a, b, c };";
+  BindableMatcher<Decl> getPattern() { return enumDecl(hasName("X")); }
+  Language getLang() { return Lang_CXX11; }
+};
+
 struct EnumConstant {
   using DeclTy = EnumConstantDecl;
   static constexpr auto *Definition = "enum E { X = 0 };";
@@ -397,6 +405,9 @@ ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE(
     Enum, Liberal, ,
     ImportConflictingDefAfterDef)
 ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE(
+    EnumClass, Liberal, ,
+    ImportConflictingDefAfterDef)
+ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE(
     EnumConstant, Liberal, ,
     ImportConflictingDefAfterDef)
 ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE(
@@ -435,6 +446,9 @@ ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE(
     Enum, Conservative, ,
     DontImportConflictingDefAfterDef)
 ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE(
+    EnumClass, Conservative, ,
+    DontImportConflictingDefAfterDef)
+ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE(
     EnumConstant, Conservative, ,
     DontImportConflictingDefAfterDef)
 ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE(
@@ -596,6 +610,9 @@ INSTANTIATE_TEST_CASE_P(
     ODRViolationTests, EnumConservative,
     DefaultTestValuesForRunOptions, );
 INSTANTIATE_TEST_CASE_P(
+    ODRViolationTests, EnumClassConservative,
+    DefaultTestValuesForRunOptions, );
+INSTANTIATE_TEST_CASE_P(
     ODRViolationTests, EnumConstantConservative,
     DefaultTestValuesForRunOptions, );
 INSTANTIATE_TEST_CASE_P(
@@ -641,6 +658,9 @@ INSTANTIATE_TEST_CASE_P(
     ODRViolationTests, EnumLiberal,
     DefaultTestValuesForRunOptions, );
 INSTANTIATE_TEST_CASE_P(
+    ODRViolationTests, EnumClassLiberal,
+    DefaultTestValuesForRunOptions, );
+INSTANTIATE_TEST_CASE_P(
     ODRViolationTests, EnumConstantLiberal,
     DefaultTestValuesForRunOptions, );
 INSTANTIATE_TEST_CASE_P(
index d00829f..14a6706 100644 (file)
@@ -69,6 +69,8 @@ const auto *AnonC = "namespace { class X; }";
 // EnumDecl:
 const auto *ExternE = "enum E {};";
 const auto *AnonE = "namespace { enum E {}; }";
+const auto *ExternEC = "enum class E;";
+const auto *AnonEC = "namespace { enum class E; }";
 // TypedefNameDecl:
 const auto *ExternTypedef = "typedef int T;";
 const auto *AnonTypedef = "namespace { typedef int T; }";
@@ -125,6 +127,7 @@ protected:
 using ImportFunctionsVisibilityChain = ImportVisibilityChain<GetFunPattern>;
 using ImportVariablesVisibilityChain = ImportVisibilityChain<GetVarPattern>;
 using ImportClassesVisibilityChain = ImportVisibilityChain<GetClassPattern>;
+using ImportScopedEnumsVisibilityChain = ImportVisibilityChain<GetEnumPattern>;
 using ImportFunctionTemplatesVisibilityChain =
     ImportVisibilityChain<GetFunTemplPattern>;
 using ImportClassTemplatesVisibilityChain =
@@ -142,6 +145,10 @@ TEST_P(ImportVariablesVisibilityChain, ImportChain) {
 TEST_P(ImportClassesVisibilityChain, ImportChain) {
   TypedTest_ImportChain();
 }
+// Value-parameterized test for scoped enums.
+TEST_P(ImportScopedEnumsVisibilityChain, ImportChain) {
+  TypedTest_ImportChain();
+}
 // Value-parameterized test for function templates.
 TEST_P(ImportFunctionTemplatesVisibilityChain, ImportChain) {
   TypedTest_ImportChain();
@@ -173,6 +180,11 @@ INSTANTIATE_TEST_CASE_P(
     ::testing::Combine(
         DefaultTestValuesForRunOptions,
         ::testing::Values(ExternC, AnonC)), );
+INSTANTIATE_TEST_CASE_P(
+    ParameterizedTests, ImportScopedEnumsVisibilityChain,
+    ::testing::Combine(
+        DefaultTestValuesForRunOptions,
+        ::testing::Values(ExternEC, AnonEC)), );
 INSTANTIATE_TEST_CASE_P(ParameterizedTests,
                         ImportFunctionTemplatesVisibilityChain,
                         ::testing::Combine(DefaultTestValuesForRunOptions,
@@ -291,6 +303,7 @@ using ImportFunctionsVisibility = ImportVisibility<GetFunPattern>;
 using ImportVariablesVisibility = ImportVisibility<GetVarPattern>;
 using ImportClassesVisibility = ImportVisibility<GetClassPattern>;
 using ImportEnumsVisibility = ImportVisibility<GetEnumPattern>;
+using ImportScopedEnumsVisibility = ImportVisibility<GetEnumPattern>;
 using ImportTypedefNameVisibility = ImportVisibility<GetTypedefNamePattern>;
 using ImportFunctionTemplatesVisibility = ImportVisibility<GetFunTemplPattern>;
 using ImportClassTemplatesVisibility = ImportVisibility<GetClassTemplPattern>;
@@ -323,6 +336,12 @@ TEST_P(ImportEnumsVisibility, ImportAfter) {
 TEST_P(ImportEnumsVisibility, ImportAfterImport) {
   TypedTest_ImportAfterImportWithMerge();
 }
+TEST_P(ImportScopedEnumsVisibility, ImportAfter) {
+  TypedTest_ImportAfter();
+}
+TEST_P(ImportScopedEnumsVisibility, ImportAfterImport) {
+  TypedTest_ImportAfterImport();
+}
 // TypedefNameDecl.
 TEST_P(ImportTypedefNameVisibility, ImportAfter) {
   TypedTest_ImportAfterWithMerge();
@@ -393,6 +412,15 @@ INSTANTIATE_TEST_CASE_P(
             std::make_tuple(AnonE, ExternE, ExpectUnlinkedDeclChain),
             std::make_tuple(AnonE, AnonE, ExpectUnlinkedDeclChain))), );
 INSTANTIATE_TEST_CASE_P(
+    ParameterizedTests, ImportScopedEnumsVisibility,
+    ::testing::Combine(
+        DefaultTestValuesForRunOptions,
+        ::testing::Values(
+            std::make_tuple(ExternEC, ExternEC, ExpectLinkedDeclChain),
+            std::make_tuple(ExternEC, AnonEC, ExpectUnlinkedDeclChain),
+            std::make_tuple(AnonEC, ExternEC, ExpectUnlinkedDeclChain),
+            std::make_tuple(AnonEC, AnonEC, ExpectUnlinkedDeclChain))), );
+INSTANTIATE_TEST_CASE_P(
     ParameterizedTests, ImportTypedefNameVisibility,
     ::testing::Combine(
         DefaultTestValuesForRunOptions,