-
Notifications
You must be signed in to change notification settings - Fork 13.4k
[clang][ASTImporter] Fix AST import if anonymous namespaces are merged #128735
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-clang Author: Balázs Kéri (balazske) ChangesI discovered one faulty case that is shown in the second of the added tests (an anonymous namespace is imported that resides in a Full diff: https://github.com/llvm/llvm-project/pull/128735.diff 2 Files Affected:
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 43da76e14d0a3..0b6ce3a377207 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -2638,11 +2638,12 @@ ExpectedDecl ASTNodeImporter::VisitNamespaceDecl(NamespaceDecl *D) {
if (!Name) {
// This is an anonymous namespace. Adopt an existing anonymous
// namespace if we can.
- // FIXME: Not testable.
- if (auto *TU = dyn_cast<TranslationUnitDecl>(DC))
+ DeclContext *EnclosingDC = DC->getEnclosingNamespaceContext();
+ if (auto *TU = dyn_cast<TranslationUnitDecl>(EnclosingDC))
MergeWithNamespace = TU->getAnonymousNamespace();
else
- MergeWithNamespace = cast<NamespaceDecl>(DC)->getAnonymousNamespace();
+ MergeWithNamespace =
+ cast<NamespaceDecl>(EnclosingDC)->getAnonymousNamespace();
} else {
SmallVector<NamedDecl *, 4> ConflictingDecls;
auto FoundDecls = Importer.findDeclsInToCtx(DC, Name);
diff --git a/clang/unittests/AST/ASTImporterTest.cpp b/clang/unittests/AST/ASTImporterTest.cpp
index 0bac95eb40b20..07714ff45a4de 100644
--- a/clang/unittests/AST/ASTImporterTest.cpp
+++ b/clang/unittests/AST/ASTImporterTest.cpp
@@ -10492,6 +10492,79 @@ TEST_P(ASTImporterOptionSpecificTestBase,
EXPECT_EQ(ToFr1Imp, ToFr1);
}
+struct ImportAndMergeAnonymousNamespace
+ : public ASTImporterOptionSpecificTestBase {
+protected:
+ void test(const char *ToCode, const char *FromCode) {
+ Decl *ToTU = getToTuDecl(ToCode, Lang_CXX11);
+ Decl *FromTU = getTuDecl(FromCode, Lang_CXX11);
+ auto *FromNS = FirstDeclMatcher<NamespaceDecl>().match(
+ FromTU, namespaceDecl(isAnonymous()));
+ auto *ToNS = FirstDeclMatcher<NamespaceDecl>().match(
+ ToTU, namespaceDecl(isAnonymous()));
+ auto *FromF = FirstDeclMatcher<FunctionDecl>().match(
+ FromTU, functionDecl(hasName("f")));
+ auto *ImportedF = Import(FromF, Lang_CXX11);
+ EXPECT_TRUE(ImportedF);
+ EXPECT_EQ(ImportedF->getDeclContext(), ToNS);
+ auto *ImportedNS = Import(FromNS, Lang_CXX11);
+ EXPECT_EQ(ImportedNS, ToNS);
+ }
+};
+
+TEST_P(ImportAndMergeAnonymousNamespace, NamespaceInTU) {
+ const char *ToCode =
+ R"(
+ namespace {
+ }
+ )";
+ const char *FromCode =
+ R"(
+ namespace {
+ void f();
+ }
+ )";
+ test(ToCode, FromCode);
+}
+
+TEST_P(ImportAndMergeAnonymousNamespace, NamespaceInLinkageSpec) {
+ const char *ToCode =
+ R"(
+ extern "C" {
+ namespace {
+ }
+ }
+ )";
+ const char *FromCode =
+ R"(
+ extern "C" {
+ namespace {
+ void f();
+ }
+ }
+ )";
+ test(ToCode, FromCode);
+}
+
+TEST_P(ImportAndMergeAnonymousNamespace, NamespaceInNamespace) {
+ const char *ToCode =
+ R"(
+ namespace X {
+ namespace {
+ }
+ }
+ )";
+ const char *FromCode =
+ R"(
+ namespace X {
+ namespace {
+ void f();
+ }
+ }
+ )";
+ test(ToCode, FromCode);
+}
+
INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ASTImporterLookupTableTest,
DefaultTestValuesForRunOptions);
@@ -10578,6 +10651,9 @@ INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ImportMatrixType,
INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ImportTemplateParmDeclDefaultValue,
DefaultTestValuesForRunOptions);
+ISTANTIATE_TEST_SUITE_P(ParameterizedTests, ImportAndMergeAnonymousNamespace,
+ DefaultTestValuesForRunOptions);
+
// FIXME: Make ImportOpenCLPipe test work.
// INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ImportOpenCLPipe,
// DefaultTestValuesForRunOptions);
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did not fully understand this part of the summary I did not check for other possibilities for namespaces that are not in a TU or namespace but at least the code should handle all cases
but I take it there are cases you are not testing?
Is there a reason not to add those tests and at least if they don't pass, they can fixed a follow-up PR but we then at least have failing tests we know we need to address?
I meant that I did not verify where a namespace declaration is allowed, if it is allowed with another declaration as parent (which is not a |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This commit looks good to me, although I'm not very familiar with this area, so perhaps wait a few days for potential other feedback.
I agree that the sentence "I did not check for other possibilities for namespaces that are not in a TU or namespace but at least the code should handle all cases." should be removed from the commit message because it's confusing, but I agree that it's OK to use cast<NamespaceDecl>
in the code (and there is no need to mention this explicitly).
As I read the testcases I became a bit curious about the situations where the target and the source contain anonymous namespaces in different contexts (directly in the TU VS in an extern "C"
block VS in another namespace). What happens in those situations? Do I understand it correctly that the anonymous namespaces are not merged and should not be merged? If these are not stupid questions and this is not already tested elsewhere, then perhaps it would be nice to add a few testcases for it.
The current behavior is the same for named or anonymous namespace: If there is an existing namespace with same name in the target ("To") TU, the imported one is merged into this (this is what was wrong before this fix, the anonymous namespace was not merged if it was inside a |
If there is only one anonymous namespace for each TU, then what does the AST import do in a situation like TEST_P(ImportAndMergeAnonymousNamespace, NamespaceInLinkageSpec) {
const char *ToCode =
R"(
extern "C" {
namespace {
}
}
)";
const char *FromCode =
R"(
namespace {
void f();
}
)";
test(ToCode, FromCode);
} where one side is within an Are these two anonymous namespaces merged by the ASTImporter code? Does this behavior cause incorrect/problematic behavior? |
I am now not really sure what happens, if there is a single anonymous namespace for a TU or there are separate ones for the anonymous namespaces in for example |
llvm#128735) Fix of a faulty case that is shown in the second of the added tests (an anonymous namespace is imported that resides in a `extern "C"` block).
I discovered one faulty case that is shown in the second of the added tests (an anonymous namespace is imported that resides in a
extern "C"
block). I did not check for other possibilities for namespaces that are not in a TU or namespace but at least the code should handle all cases.