summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/include/clang/AST/ASTImporter.h7
-rw-r--r--clang/lib/AST/ASTImporter.cpp47
-rw-r--r--clang/test/ASTMerge/unnamed_fields/Inputs/il.cpp3
-rw-r--r--clang/test/ASTMerge/unnamed_fields/test.cpp3
-rw-r--r--clang/unittests/AST/ASTImporterTest.cpp34
5 files changed, 75 insertions, 19 deletions
diff --git a/clang/include/clang/AST/ASTImporter.h b/clang/include/clang/AST/ASTImporter.h
index 2e9a8775a8a..311d64e7cbf 100644
--- a/clang/include/clang/AST/ASTImporter.h
+++ b/clang/include/clang/AST/ASTImporter.h
@@ -333,6 +333,13 @@ class Attr;
/// equivalent.
bool IsStructurallyEquivalent(QualType From, QualType To,
bool Complain = true);
+
+ /// Determine the index of a field in its parent record.
+ /// F should be a field (or indirect field) declaration.
+ /// \returns The index of the field in its parent context, starting from 1.
+ /// 0 is returned on error (parent context is non-record).
+ static unsigned getFieldIndex(Decl *F);
+
};
} // namespace clang
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 38ad4e28931..791dcc747cc 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -71,6 +71,28 @@
namespace clang {
+ unsigned ASTImporter::getFieldIndex(Decl *F) {
+ assert(F && (isa<FieldDecl>(*F) || isa<IndirectFieldDecl>(*F)) &&
+ "Try to get field index for non-field.");
+
+ auto *Owner = dyn_cast<RecordDecl>(F->getDeclContext());
+ if (!Owner)
+ return 0;
+
+ unsigned Index = 1;
+ for (const auto *D : Owner->decls()) {
+ if (D == F)
+ return Index;
+
+ if (isa<FieldDecl>(*D) || isa<IndirectFieldDecl>(*D))
+ ++Index;
+ }
+
+ llvm_unreachable("Field was not found in its parent context.");
+
+ return 0;
+ }
+
template <class T>
SmallVector<Decl*, 2>
getCanonicalForwardRedeclChain(Redeclarable<T>* D) {
@@ -2829,23 +2851,6 @@ Decl *ASTNodeImporter::VisitCXXConversionDecl(CXXConversionDecl *D) {
return VisitCXXMethodDecl(D);
}
-static unsigned getFieldIndex(Decl *F) {
- auto *Owner = dyn_cast<RecordDecl>(F->getDeclContext());
- if (!Owner)
- return 0;
-
- unsigned Index = 1;
- for (const auto *D : Owner->noload_decls()) {
- if (D == F)
- return Index;
-
- if (isa<FieldDecl>(*D) || isa<IndirectFieldDecl>(*D))
- ++Index;
- }
-
- return Index;
-}
-
Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) {
// Import the major distinguishing characteristics of a variable.
DeclContext *DC, *LexicalDC;
@@ -2863,7 +2868,9 @@ Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) {
for (auto *FoundDecl : FoundDecls) {
if (auto *FoundField = dyn_cast<FieldDecl>(FoundDecl)) {
// For anonymous fields, match up by index.
- if (!Name && getFieldIndex(D) != getFieldIndex(FoundField))
+ if (!Name &&
+ ASTImporter::getFieldIndex(D) !=
+ ASTImporter::getFieldIndex(FoundField))
continue;
if (Importer.IsStructurallyEquivalent(D->getType(),
@@ -2928,7 +2935,9 @@ Decl *ASTNodeImporter::VisitIndirectFieldDecl(IndirectFieldDecl *D) {
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (auto *FoundField = dyn_cast<IndirectFieldDecl>(FoundDecls[I])) {
// For anonymous indirect fields, match up by index.
- if (!Name && getFieldIndex(D) != getFieldIndex(FoundField))
+ if (!Name &&
+ ASTImporter::getFieldIndex(D) !=
+ ASTImporter::getFieldIndex(FoundField))
continue;
if (Importer.IsStructurallyEquivalent(D->getType(),
diff --git a/clang/test/ASTMerge/unnamed_fields/Inputs/il.cpp b/clang/test/ASTMerge/unnamed_fields/Inputs/il.cpp
new file mode 100644
index 00000000000..1bb0f358dcf
--- /dev/null
+++ b/clang/test/ASTMerge/unnamed_fields/Inputs/il.cpp
@@ -0,0 +1,3 @@
+void f(int X, int Y, bool Z) {
+ auto x = [X, Y, Z] { (void)Z; };
+}
diff --git a/clang/test/ASTMerge/unnamed_fields/test.cpp b/clang/test/ASTMerge/unnamed_fields/test.cpp
new file mode 100644
index 00000000000..6ae3176df4f
--- /dev/null
+++ b/clang/test/ASTMerge/unnamed_fields/test.cpp
@@ -0,0 +1,3 @@
+// RUN: %clang_cc1 -emit-pch -o %t.1.ast %S/Inputs/il.cpp
+// RUN: %clang_cc1 -ast-merge %t.1.ast -fsyntax-only %s 2>&1 | FileCheck --allow-empty %s
+// CHECK-NOT: warning: field '' declared with incompatible types in different translation units ('bool' vs. 'int')
diff --git a/clang/unittests/AST/ASTImporterTest.cpp b/clang/unittests/AST/ASTImporterTest.cpp
index 04006a0bea3..2690f4e5f1f 100644
--- a/clang/unittests/AST/ASTImporterTest.cpp
+++ b/clang/unittests/AST/ASTImporterTest.cpp
@@ -2641,6 +2641,40 @@ TEST_P(ASTImporterTestBase, ImportUnnamedStructsWithRecursingField) {
R1, recordDecl(has(fieldDecl(hasName("next"))))));
}
+TEST_P(ASTImporterTestBase, ImportUnnamedFieldsInCorrectOrder) {
+ Decl *FromTU = getTuDecl(
+ R"(
+ void f(int X, int Y, bool Z) {
+ (void)[X, Y, Z] { (void)Z; };
+ }
+ )",
+ Lang_CXX11, "input0.cc");
+ auto *FromF = FirstDeclMatcher<FunctionDecl>().match(
+ FromTU, functionDecl(hasName("f")));
+ auto *ToF = cast_or_null<FunctionDecl>(Import(FromF, Lang_CXX11));
+ EXPECT_TRUE(ToF);
+
+ CXXRecordDecl *FromLambda =
+ cast<LambdaExpr>(cast<CStyleCastExpr>(cast<CompoundStmt>(
+ FromF->getBody())->body_front())->getSubExpr())->getLambdaClass();
+
+ auto *ToLambda = cast_or_null<CXXRecordDecl>(Import(FromLambda, Lang_CXX11));
+ EXPECT_TRUE(ToLambda);
+
+ // Check if the fields of the lambda class are imported in correct order.
+ unsigned FromIndex = 0u;
+ for (auto *FromField : FromLambda->fields()) {
+ ASSERT_FALSE(FromField->getDeclName());
+ auto *ToField = cast_or_null<FieldDecl>(Import(FromField, Lang_CXX11));
+ EXPECT_TRUE(ToField);
+ unsigned ToIndex = ASTImporter::getFieldIndex(ToField);
+ EXPECT_EQ(ToIndex, FromIndex + 1);
+ ++FromIndex;
+ }
+
+ EXPECT_EQ(FromIndex, 3u);
+}
+
struct DeclContextTest : ASTImporterTestBase {};
TEST_P(DeclContextTest, removeDeclOfClassTemplateSpecialization) {
OpenPOWER on IntegriCloud