summaryrefslogtreecommitdiff
path: root/test/ASTMerge
diff options
context:
space:
mode:
authorReid Kleckner <rnk@google.com>2019-05-14 18:51:07 +0000
committerReid Kleckner <rnk@google.com>2019-05-14 18:51:07 +0000
commit9ea2db92e4180cccb87f78b4d9a7bf0adb430097 (patch)
treeb1dd76395ab5f7fadfda9207cc25806b9f15c217 /test/ASTMerge
parentce15c91f4c4912cc3ea62256557dab8dbe4de7d1 (diff)
downloadclang-9ea2db92e4180cccb87f78b4d9a7bf0adb430097.tar.gz
Restore test files accidentally deleted in r354839
I think there must be a bug in git-llvm causing parent directories to be deleted when the diff deletes files in a subdirectory. Perhaps it is Windows-only. There has been a behavior change, so some of these tests now fail. I have marked them XFAIL and will fix them in a follow-up to separate the changes. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@360699 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'test/ASTMerge')
-rw-r--r--test/ASTMerge/anonymous-fields/Inputs/anonymous-fields1.cpp5
-rw-r--r--test/ASTMerge/anonymous-fields/Inputs/anonymous-fields2.cpp9
-rw-r--r--test/ASTMerge/anonymous-fields/test.cpp4
-rw-r--r--test/ASTMerge/asm/Inputs/asm-function.cpp21
-rw-r--r--test/ASTMerge/asm/test.cpp8
-rw-r--r--test/ASTMerge/category/Inputs/category1.m48
-rw-r--r--test/ASTMerge/category/Inputs/category2.m49
-rw-r--r--test/ASTMerge/category/test.m13
-rw-r--r--test/ASTMerge/class-template-partial-spec/Inputs/class-template-partial-spec1.cpp118
-rw-r--r--test/ASTMerge/class-template-partial-spec/Inputs/class-template-partial-spec2.cpp79
-rw-r--r--test/ASTMerge/class-template-partial-spec/test.cpp27
-rw-r--r--test/ASTMerge/class-template/Inputs/class-template1.cpp37
-rw-r--r--test/ASTMerge/class-template/Inputs/class-template2.cpp37
-rw-r--r--test/ASTMerge/class-template/test.cpp30
-rw-r--r--test/ASTMerge/class/Inputs/class1.cpp48
-rw-r--r--test/ASTMerge/class/Inputs/class2.cpp40
-rw-r--r--test/ASTMerge/class/test.cpp24
-rw-r--r--test/ASTMerge/class2/Inputs/class3.cpp26
-rw-r--r--test/ASTMerge/class2/test.cpp9
-rw-r--r--test/ASTMerge/codegen-body/Inputs/body1.c6
-rw-r--r--test/ASTMerge/codegen-body/Inputs/body2.c4
-rw-r--r--test/ASTMerge/codegen-body/test.c5
-rw-r--r--test/ASTMerge/codegen-exprs/Inputs/exprs1.c10
-rw-r--r--test/ASTMerge/codegen-exprs/Inputs/exprs2.c10
-rw-r--r--test/ASTMerge/codegen-exprs/test.c5
-rw-r--r--test/ASTMerge/enum/Inputs/enum1.c42
-rw-r--r--test/ASTMerge/enum/Inputs/enum2.c42
-rw-r--r--test/ASTMerge/enum/test.c27
-rw-r--r--test/ASTMerge/exprs-cpp/Inputs/exprs3.cpp141
-rw-r--r--test/ASTMerge/exprs-cpp/test.cpp50
-rw-r--r--test/ASTMerge/exprs/Inputs/exprs1.c10
-rw-r--r--test/ASTMerge/exprs/Inputs/exprs2.c10
-rw-r--r--test/ASTMerge/exprs/test.c5
-rw-r--r--test/ASTMerge/function-cpp/Inputs/function-1.cpp8
-rw-r--r--test/ASTMerge/function-cpp/test.cpp10
-rw-r--r--test/ASTMerge/function/Inputs/function1.c6
-rw-r--r--test/ASTMerge/function/Inputs/function2.c7
-rw-r--r--test/ASTMerge/function/test.c17
-rw-r--r--test/ASTMerge/inheritance/Inputs/inheritance-base.cpp7
-rw-r--r--test/ASTMerge/inheritance/test.cpp8
-rw-r--r--test/ASTMerge/init-ctors/Inputs/init-ctors-classes.cpp19
-rw-r--r--test/ASTMerge/init-ctors/test.cpp10
-rw-r--r--test/ASTMerge/injected-class-name-decl/Inputs/inject1.cpp2
-rw-r--r--test/ASTMerge/injected-class-name-decl/Inputs/inject2.cpp2
-rw-r--r--test/ASTMerge/injected-class-name-decl/test.cpp3
-rw-r--r--test/ASTMerge/interface/Inputs/interface1.m105
-rw-r--r--test/ASTMerge/interface/Inputs/interface2.m100
-rw-r--r--test/ASTMerge/interface/test.m24
-rw-r--r--test/ASTMerge/macro/Inputs/macro.modulemap4
-rw-r--r--test/ASTMerge/macro/Inputs/macro1.h5
-rw-r--r--test/ASTMerge/macro/Inputs/macro1.m5
-rw-r--r--test/ASTMerge/macro/Inputs/macro2.m5
-rw-r--r--test/ASTMerge/macro/test.m6
-rw-r--r--test/ASTMerge/namespace/Inputs/namespace1.cpp27
-rw-r--r--test/ASTMerge/namespace/Inputs/namespace2.cpp60
-rw-r--r--test/ASTMerge/namespace/test.cpp19
-rw-r--r--test/ASTMerge/property/Inputs/property1.m31
-rw-r--r--test/ASTMerge/property/Inputs/property2.m33
-rw-r--r--test/ASTMerge/property/test.m15
-rw-r--r--test/ASTMerge/std-initializer-list/Inputs/il.cpp9
-rw-r--r--test/ASTMerge/std-initializer-list/test.cpp3
-rw-r--r--test/ASTMerge/struct/Inputs/struct1.c141
-rw-r--r--test/ASTMerge/struct/Inputs/struct2.c138
-rw-r--r--test/ASTMerge/struct/test.c57
-rw-r--r--test/ASTMerge/typedef/Inputs/typedef1.c4
-rw-r--r--test/ASTMerge/typedef/Inputs/typedef2.c4
-rw-r--r--test/ASTMerge/typedef/test.c9
-rw-r--r--test/ASTMerge/unnamed_fields/Inputs/il.cpp3
-rw-r--r--test/ASTMerge/unnamed_fields/test.cpp3
-rw-r--r--test/ASTMerge/var-cpp/Inputs/var1.cpp17
-rw-r--r--test/ASTMerge/var-cpp/test.cpp9
-rw-r--r--test/ASTMerge/var/Inputs/var1.c7
-rw-r--r--test/ASTMerge/var/Inputs/var1.h1
-rw-r--r--test/ASTMerge/var/Inputs/var2.c7
-rw-r--r--test/ASTMerge/var/test.c14
75 files changed, 1963 insertions, 0 deletions
diff --git a/test/ASTMerge/anonymous-fields/Inputs/anonymous-fields1.cpp b/test/ASTMerge/anonymous-fields/Inputs/anonymous-fields1.cpp
new file mode 100644
index 0000000000..829bc0edd3
--- /dev/null
+++ b/test/ASTMerge/anonymous-fields/Inputs/anonymous-fields1.cpp
@@ -0,0 +1,5 @@
+class A {
+public:
+ struct { int foo; } f;
+ struct { int foo; } g;
+};
diff --git a/test/ASTMerge/anonymous-fields/Inputs/anonymous-fields2.cpp b/test/ASTMerge/anonymous-fields/Inputs/anonymous-fields2.cpp
new file mode 100644
index 0000000000..28ea46d987
--- /dev/null
+++ b/test/ASTMerge/anonymous-fields/Inputs/anonymous-fields2.cpp
@@ -0,0 +1,9 @@
+class A {
+public:
+ struct { int foo; } f;
+ struct { int foo; } g;
+};
+
+inline int useA(A &a) {
+ return (a.f.foo + a.g.foo);
+}
diff --git a/test/ASTMerge/anonymous-fields/test.cpp b/test/ASTMerge/anonymous-fields/test.cpp
new file mode 100644
index 0000000000..67afc29d07
--- /dev/null
+++ b/test/ASTMerge/anonymous-fields/test.cpp
@@ -0,0 +1,4 @@
+// RUN: %clang_cc1 -emit-pch -o %t.1.ast %S/Inputs/anonymous-fields1.cpp
+// RUN: %clang_cc1 -emit-pch -o %t.2.ast %S/Inputs/anonymous-fields2.cpp
+// RUN: %clang_cc1 -emit-obj -o /dev/null -ast-merge %t.1.ast -ast-merge %t.2.ast %s
+// expected-no-diagnostics
diff --git a/test/ASTMerge/asm/Inputs/asm-function.cpp b/test/ASTMerge/asm/Inputs/asm-function.cpp
new file mode 100644
index 0000000000..1b8783354f
--- /dev/null
+++ b/test/ASTMerge/asm/Inputs/asm-function.cpp
@@ -0,0 +1,21 @@
+
+unsigned char asmFunc(unsigned char a, unsigned char b) {
+ unsigned int la = a;
+ unsigned int lb = b;
+ unsigned int bigres;
+ unsigned char res;
+ __asm__ ("0:\n1:\n" : [bigres] "=la"(bigres) : [la] "0"(la), [lb] "c"(lb) :
+ "edx", "cc");
+ res = bigres;
+ return res;
+}
+
+int asmFunc2(int i) {
+ int res;
+ asm ("mov %1, %0 \t\n"
+ "inc %0 "
+ : "=r" (res)
+ : "r" (i)
+ : "cc");
+ return res;
+}
diff --git a/test/ASTMerge/asm/test.cpp b/test/ASTMerge/asm/test.cpp
new file mode 100644
index 0000000000..8c3bdfe17b
--- /dev/null
+++ b/test/ASTMerge/asm/test.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -triple i386-unknown-unknown -fcxx-exceptions -emit-pch -o %t.1.ast %S/Inputs/asm-function.cpp
+// RUN: %clang_cc1 -triple i386-unknown-unknown -fcxx-exceptions -ast-merge %t.1.ast -fsyntax-only -verify %s
+// expected-no-diagnostics
+
+void testAsmImport() {
+ asmFunc(12, 42);
+ asmFunc2(42);
+}
diff --git a/test/ASTMerge/category/Inputs/category1.m b/test/ASTMerge/category/Inputs/category1.m
new file mode 100644
index 0000000000..afcaab81f2
--- /dev/null
+++ b/test/ASTMerge/category/Inputs/category1.m
@@ -0,0 +1,48 @@
+@interface I1
+@end
+
+// Matching category
+@interface I1 (Cat1)
+- (int)method0;
+@end
+
+// Matching class extension
+@interface I1 ()
+- (int)method1;
+@end
+
+// Mismatched category
+@interface I1 (Cat2)
+- (int)method2;
+@end
+
+@interface I2
+@end
+
+// Mismatched class extension
+@interface I2 ()
+- (int)method3;
+@end
+
+// Category with implementation
+@interface I2 (Cat3)
+@end
+
+@implementation I2 (Cat3)
+@end
+
+// Category with implementation
+@interface I2 (Cat4)
+@end
+
+@implementation I2 (Cat4)
+@end
+
+// Category with mismatched implementation
+@interface I2 (Cat6)
+@end
+
+@implementation I2 (Cat6)
+- (float)blah { return 0; }
+@end
+
diff --git a/test/ASTMerge/category/Inputs/category2.m b/test/ASTMerge/category/Inputs/category2.m
new file mode 100644
index 0000000000..49a3c270a1
--- /dev/null
+++ b/test/ASTMerge/category/Inputs/category2.m
@@ -0,0 +1,49 @@
+typedef int Int;
+
+@interface I1
+@end
+
+// Matching category
+@interface I1 (Cat1)
+- (Int)method0;
+@end
+
+// Matching class extension
+@interface I1 ()
+- (Int)method1;
+@end
+
+// Mismatched category
+@interface I1 (Cat2)
+- (float)method2;
+@end
+
+@interface I2
+@end
+
+// Mismatched class extension
+@interface I2 ()
+- (float)method3;
+@end
+
+// Category with implementation
+@interface I2 (Cat3)
+@end
+
+@implementation I2 (Cat3)
+@end
+
+// Category with implementation
+@interface I2 (Cat5)
+@end
+
+@implementation I2 (Cat5)
+@end
+
+// Category with mismatched implementation
+@interface I2 (Cat6)
+@end
+
+@implementation I2 (Cat6)
+- (int)blah { return 0; }
+@end
diff --git a/test/ASTMerge/category/test.m b/test/ASTMerge/category/test.m
new file mode 100644
index 0000000000..bee72f6756
--- /dev/null
+++ b/test/ASTMerge/category/test.m
@@ -0,0 +1,13 @@
+// FIXME: Errors are now warnings.
+// XFAIL: *
+// RUN: %clang_cc1 -emit-pch -o %t.1.ast %S/Inputs/category1.m
+// RUN: %clang_cc1 -emit-pch -o %t.2.ast %S/Inputs/category2.m
+// RUN: not %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1 | FileCheck %s
+
+// CHECK: category2.m:18:1: error: instance method 'method2' has incompatible result types in different translation units ('float' vs. 'int')
+// CHECK: category1.m:16:1: note: instance method 'method2' also declared here
+// CHECK: category2.m:26:1: error: instance method 'method3' has incompatible result types in different translation units ('float' vs. 'int')
+// CHECK: category1.m:24:1: note: instance method 'method3' also declared here
+// CHECK: category2.m:48:1: error: instance method 'blah' has incompatible result types in different translation units ('int' vs. 'float')
+// CHECK: category1.m:46:1: note: instance method 'blah' also declared here
+// CHECK: 3 errors generated.
diff --git a/test/ASTMerge/class-template-partial-spec/Inputs/class-template-partial-spec1.cpp b/test/ASTMerge/class-template-partial-spec/Inputs/class-template-partial-spec1.cpp
new file mode 100644
index 0000000000..43606d4d22
--- /dev/null
+++ b/test/ASTMerge/class-template-partial-spec/Inputs/class-template-partial-spec1.cpp
@@ -0,0 +1,118 @@
+template<typename T, class P>
+struct TwoOptionTemplate {};
+
+template<typename T>
+struct TwoOptionTemplate<T, char> {
+ int member;
+};
+
+
+template<typename T>
+struct TwoOptionTemplate<T, double> {
+ float member;
+};
+
+template<typename T>
+struct TwoOptionTemplate<T, T> {
+ T** member;
+};
+
+TwoOptionTemplate<int, char> X0;
+TwoOptionTemplate<int, float> X1;
+TwoOptionTemplate<void *, wchar_t> X2;
+TwoOptionTemplate<long, long> X3;
+TwoOptionTemplate<float, float> X4;
+TwoOptionTemplate<long, long> SingleSource;
+TwoOptionTemplate<char, double> SecondDoubleSource;
+
+
+template<int I, class C>
+struct IntTemplateSpec {};
+
+template<class C>
+struct IntTemplateSpec<4, C> {
+ C member;
+};
+
+template<int I>
+struct IntTemplateSpec<I, void *> {
+ int member;
+ static constexpr int val = I;
+};
+
+template<int I>
+struct IntTemplateSpec<I, double> {
+ char member;
+ static constexpr int val = I;
+};
+
+IntTemplateSpec<4, wchar_t> Y0;
+IntTemplateSpec<5, void *> Y1;
+IntTemplateSpec<1, long> Y2;
+IntTemplateSpec<3, int> Y3;
+//template<int I> constexpr int IntTemplateSpec<I, double>::val;
+IntTemplateSpec<42, double> NumberSource;
+static_assert(NumberSource.val == 42);
+
+namespace One {
+namespace Two {
+ // Just an empty namespace to ensure we can deal with multiple namespace decls.
+}
+}
+
+
+namespace One {
+namespace Two {
+namespace Three {
+
+template<class T>
+class Parent {};
+
+} // namespace Three
+
+} // namespace Two
+
+template<typename T, typename X>
+struct Child1: public Two::Three::Parent<unsigned> {
+ char member;
+};
+
+template<class T>
+struct Child1<T, One::Two::Three::Parent<T>> {
+ T member;
+};
+
+} // namespace One
+
+One::Child1<int, double> Z0Source;
+
+// Test import of nested namespace specifiers
+template<typename T>
+struct Outer {
+ template<typename U> class Inner0;
+};
+
+template<typename X>
+template<typename Y>
+class Outer<X>::Inner0 {
+public:
+ void f(X, Y);
+ template<typename Z> struct Inner1;
+};
+
+template<typename X>
+template<typename Y>
+void Outer<X>::Inner0<Y>::f(X, Y) {}
+
+template<typename X>
+template<typename Y>
+template<typename Z>
+class Outer<X>::Inner0<Y>::Inner1 {
+public:
+ void f(Y, Z);
+};
+
+template<typename X>
+template<typename Y>
+template<typename Z>
+void Outer<X>::Inner0<Y>::Inner1<Z>::f(Y, Z) {}
diff --git a/test/ASTMerge/class-template-partial-spec/Inputs/class-template-partial-spec2.cpp b/test/ASTMerge/class-template-partial-spec/Inputs/class-template-partial-spec2.cpp
new file mode 100644
index 0000000000..2f3f0c68e2
--- /dev/null
+++ b/test/ASTMerge/class-template-partial-spec/Inputs/class-template-partial-spec2.cpp
@@ -0,0 +1,79 @@
+template<typename T, typename P>
+struct TwoOptionTemplate {};
+
+template<typename T>
+struct TwoOptionTemplate<T, char> {
+ int member;
+};
+
+
+template<typename T>
+struct TwoOptionTemplate<T, double> {
+ float member;
+};
+
+template<typename T>
+struct TwoOptionTemplate<T, T> {
+ T** member;
+};
+
+TwoOptionTemplate<int, char> X0;
+TwoOptionTemplate<int, double> X1;
+TwoOptionTemplate<void *, wchar_t> X2;
+TwoOptionTemplate<long, long> X3;
+TwoOptionTemplate<int, int> X4;
+TwoOptionTemplate<long, long> SingleDest;
+TwoOptionTemplate<int, double> SecondDoubleDest;
+
+
+template<int I, class C>
+struct IntTemplateSpec {};
+
+template<class C>
+struct IntTemplateSpec<4, C> {
+ C member;
+};
+
+template<int I>
+struct IntTemplateSpec<I, void *> {
+ double member;
+ static constexpr int val = I;
+};
+
+template<int I>
+struct IntTemplateSpec<I, double> {
+ char member;
+ static constexpr int val = I;
+};
+
+IntTemplateSpec<4, wchar_t>Y0;
+IntTemplateSpec<5, void *> Y1;
+IntTemplateSpec<1, int> Y2;
+IntTemplateSpec<2, int> Y3;
+IntTemplateSpec<43, double> NumberDest;
+
+namespace One {
+namespace Two {
+namespace Three {
+
+template<class T>
+class Parent {};
+
+} // namespace Three
+
+} // namespace Two
+
+template<typename T, typename X>
+struct Child1: public Two::Three::Parent<unsigned> {
+ char member;
+};
+
+template<class T>
+struct Child1<T, One::Two::Three::Parent<T>> {
+ T member;
+};
+
+} // namespace One
+
+namespace Dst { One::Child1<double, One::Two::Three::Parent<double>> Z0Dst; }
+One::Child1<int, float> Z1;
diff --git a/test/ASTMerge/class-template-partial-spec/test.cpp b/test/ASTMerge/class-template-partial-spec/test.cpp
new file mode 100644
index 0000000000..9aa4ab5e3c
--- /dev/null
+++ b/test/ASTMerge/class-template-partial-spec/test.cpp
@@ -0,0 +1,27 @@
+// FIXME: Errors are now warnings.
+// XFAIL: *
+// RUN: %clang_cc1 -emit-pch -std=c++1z -o %t.1.ast %S/Inputs/class-template-partial-spec1.cpp
+// RUN: %clang_cc1 -emit-pch -std=c++1z -o %t.2.ast %S/Inputs/class-template-partial-spec2.cpp
+// RUN: not %clang_cc1 -std=c++1z -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1 | FileCheck %s
+
+static_assert(sizeof(**SingleSource.member) == sizeof(**SingleDest.member));
+static_assert(sizeof(SecondDoubleSource.member) == sizeof(SecondDoubleDest.member));
+static_assert(NumberSource.val == 42);
+static_assert(sizeof(Z0Source.member) == sizeof(char));
+static_assert(sizeof(Dst::Z0Dst.member) == sizeof(double));
+static_assert(sizeof(One::Child1<double, One::Two::Three::Parent<double>>::member) == sizeof(double));
+
+// CHECK: class-template-partial-spec2.cpp:21:32: error: external variable 'X1' declared with incompatible types in different translation units ('TwoOptionTemplate<int, double>' vs. 'TwoOptionTemplate<int, float>')
+// CHECK: class-template-partial-spec1.cpp:21:31: note: declared here with type 'TwoOptionTemplate<int, float>'
+
+// CHECK: class-template-partial-spec2.cpp:24:29: error: external variable 'X4' declared with incompatible types in different translation units ('TwoOptionTemplate<int, int>' vs. 'TwoOptionTemplate<float, float>')
+// CHECK: class-template-partial-spec1.cpp:24:33: note: declared here with type 'TwoOptionTemplate<float, float>'
+
+// CHECK: class-template-partial-spec1.cpp:38:8: warning: type 'IntTemplateSpec<5, void *>' has incompatible definitions in different translation units
+// CHECK: class-template-partial-spec1.cpp:39:7: note: field 'member' has type 'int' here
+// CHECK: class-template-partial-spec2.cpp:39:10: note: field 'member' has type 'double' here
+
+// CHECK: class-template-partial-spec2.cpp:52:25: error: external variable 'Y3' declared with incompatible types in different translation units ('IntTemplateSpec<2, int>' vs. 'IntTemplateSpec<3, int>')
+// CHECK: class-template-partial-spec1.cpp:52:25: note: declared here with type 'IntTemplateSpec<3, int>'
+
+// CHECK-NOT: static_assert
diff --git a/test/ASTMerge/class-template/Inputs/class-template1.cpp b/test/ASTMerge/class-template/Inputs/class-template1.cpp
new file mode 100644
index 0000000000..fb5b229e0a
--- /dev/null
+++ b/test/ASTMerge/class-template/Inputs/class-template1.cpp
@@ -0,0 +1,37 @@
+template<typename T>
+struct X0 {
+ T getValue(T arg) { return arg; }
+};
+
+template<int I>
+struct X1;
+
+template<int I>
+struct X2;
+
+template<int I>
+struct X3;
+
+template<template<int I> class>
+struct X4;
+
+template<template<long> class>
+struct X5;
+
+template<typename>
+struct X6;
+
+extern X0<int> *x0i;
+extern X0<long> *x0l;
+extern X0<float> *x0r;
+
+template<>
+struct X0<char> {
+ int member;
+ char getValue(char ch) { return static_cast<char>(member); }
+};
+
+template<>
+struct X0<wchar_t> {
+ int member;
+};
diff --git a/test/ASTMerge/class-template/Inputs/class-template2.cpp b/test/ASTMerge/class-template/Inputs/class-template2.cpp
new file mode 100644
index 0000000000..b5d0add13f
--- /dev/null
+++ b/test/ASTMerge/class-template/Inputs/class-template2.cpp
@@ -0,0 +1,37 @@
+template<class T>
+struct X0 {
+ T getValue(T arg);
+};
+
+template<int I>
+struct X1;
+
+template<long I>
+struct X2;
+
+template<typename>
+struct X3;
+
+template<template<int I> class>
+struct X4;
+
+template<template<int I> class>
+struct X5;
+
+template<template<int I> class>
+struct X6;
+
+typedef int Integer;
+extern X0<Integer> *x0i;
+extern X0<float> *x0f;
+extern X0<double> *x0r;
+
+template<>
+struct X0<char> {
+ int member;
+};
+
+template<>
+struct X0<wchar_t> {
+ float member;
+};
diff --git a/test/ASTMerge/class-template/test.cpp b/test/ASTMerge/class-template/test.cpp
new file mode 100644
index 0000000000..f2ac4c5a63
--- /dev/null
+++ b/test/ASTMerge/class-template/test.cpp
@@ -0,0 +1,30 @@
+// FIXME: Errors are now warnings.
+// XFAIL: *
+// RUN: %clang_cc1 -std=c++1z -emit-pch -o %t.1.ast %S/Inputs/class-template1.cpp
+// RUN: %clang_cc1 -std=c++1z -emit-pch -o %t.2.ast %S/Inputs/class-template2.cpp
+// RUN: not %clang_cc1 -std=c++1z -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1 | FileCheck %s
+
+static_assert(sizeof(X0<char>().getValue(1)) == sizeof(char));
+static_assert(sizeof(X0<int>().getValue(1)) == sizeof(int));
+
+// CHECK: class-template1.cpp:9:14: error: non-type template parameter declared with incompatible types in different translation units ('int' vs. 'long')
+// CHECK: class-template2.cpp:9:15: note: declared here with type 'long'
+
+// CHECK: class-template1.cpp:12:14: error: template parameter has different kinds in different translation units
+// CHECK: class-template2.cpp:12:10: note: template parameter declared here
+
+// CHECK: class-template1.cpp:18:23: error: non-type template parameter declared with incompatible types in different translation units ('long' vs. 'int')
+// CHECK: class-template2.cpp:18:23: note: declared here with type 'int'
+
+// CHECK: class-template1.cpp:21:10: error: template parameter has different kinds in different translation units
+// CHECK: class-template2.cpp:21:10: note: template parameter declared here
+
+// CHECK: class-template2.cpp:27:20: error: external variable 'x0r' declared with incompatible types in different translation units ('X0<double> *' vs. 'X0<float> *')
+// CHECK: class-template1.cpp:26:19: note: declared here with type 'X0<float> *'
+
+// CHECK: class-template1.cpp:35:8: warning: type 'X0<wchar_t>' has incompatible definitions in different translation units
+// CHECK: class-template1.cpp:36:7: note: field 'member' has type 'int' here
+// CHECK: class-template2.cpp:36:9: note: field 'member' has type 'float' here
+
+// CHECK: 1 warning and 5 errors generated.
+// CHECK-NOT: static_assert
diff --git a/test/ASTMerge/class/Inputs/class1.cpp b/test/ASTMerge/class/Inputs/class1.cpp
new file mode 100644
index 0000000000..2bd5503ecf
--- /dev/null
+++ b/test/ASTMerge/class/Inputs/class1.cpp
@@ -0,0 +1,48 @@
+struct A {
+ public:
+ int x;
+};
+
+struct B : A {
+ float y;
+ float foo();
+};
+
+struct C {
+ C(int i = 10);
+ C(const C&);
+ C &operator=(C&);
+ ~C();
+};
+
+enum E {
+ b = 1
+};
+
+//Friend import tests
+void f();
+int g(int a);
+struct X;
+struct Y;
+
+struct F1 {
+public:
+ int x;
+ friend struct X;
+ friend int g(int);
+ friend void f();
+};
+
+struct F2 {
+public:
+ int x;
+ friend struct X;
+ friend void f();
+};
+
+struct F3 {
+public:
+ int x;
+ friend int g(int);
+ friend void f();
+};
diff --git a/test/ASTMerge/class/Inputs/class2.cpp b/test/ASTMerge/class/Inputs/class2.cpp
new file mode 100644
index 0000000000..6fe38b9206
--- /dev/null
+++ b/test/ASTMerge/class/Inputs/class2.cpp
@@ -0,0 +1,40 @@
+struct A {
+ public:
+ int x;
+};
+
+struct B : A {
+ int y;
+ int foo();
+};
+
+enum E {
+ a = 0,
+ b = 1
+};
+
+//Friend import tests
+void f();
+int g(int a);
+struct X;
+struct Y;
+
+struct F1 {
+public:
+ int x;
+ friend struct X;
+ friend int g(int);
+ friend void f();
+};
+
+struct F2 {
+public:
+ int x;
+ friend struct X;
+};
+
+struct F3 {
+public:
+ int x;
+ friend void f();
+};
diff --git a/test/ASTMerge/class/test.cpp b/test/ASTMerge/class/test.cpp
new file mode 100644
index 0000000000..ba553af407
--- /dev/null
+++ b/test/ASTMerge/class/test.cpp
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -emit-pch -o %t.1.ast %S/Inputs/class1.cpp
+// RUN: %clang_cc1 -emit-pch -o %t.2.ast %S/Inputs/class2.cpp
+// RUN: %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1 | FileCheck %s
+// RUN: %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1 -Wno-odr -Werror
+
+// CHECK: class1.cpp:6:8: warning: type 'B' has incompatible definitions in different translation units
+// CHECK: class1.cpp:7:9: note: field 'y' has type 'float' here
+// CHECK: class2.cpp:7:7: note: field 'y' has type 'int' here
+
+// FIXME: we should also complain about mismatched types on the method
+
+// CHECK: class1.cpp:18:6: warning: type 'E' has incompatible definitions in different translation units
+// CHECK: class1.cpp:19:3: note: enumerator 'b' with value 1 here
+// CHECK: class2.cpp:12:3: note: enumerator 'a' with value 0 here
+
+// CHECK: class1.cpp:43:8: warning: type 'F3' has incompatible definitions in different translation units
+// CHECK: class1.cpp:46:3: note: friend declared here
+// CHECK: class2.cpp:36:8: note: no corresponding friend here
+
+// CHECK: class1.cpp:36:8: warning: type 'F2' has incompatible definitions in different translation units
+// CHECK: class1.cpp:39:3: note: friend declared here
+// CHECK: class2.cpp:30:8: note: no corresponding friend here
+
+// CHECK: 4 warnings generated.
diff --git a/test/ASTMerge/class2/Inputs/class3.cpp b/test/ASTMerge/class2/Inputs/class3.cpp
new file mode 100644
index 0000000000..428acc3f03
--- /dev/null
+++ b/test/ASTMerge/class2/Inputs/class3.cpp
@@ -0,0 +1,26 @@
+class C1 {
+public:
+ C1();
+ ~C1();
+ C1 *method_1() {
+ return this;
+ }
+ C1 method_2() {
+ return C1();
+ }
+ void method_3() {
+ const C1 &ref = C1();
+ }
+};
+
+class C11 : public C1 {
+};
+
+class C2 {
+private:
+ int x;
+ friend class C3;
+public:
+ static_assert(sizeof(x) == sizeof(int), "Error");
+ typedef class C2::C2 InjType;
+};
diff --git a/test/ASTMerge/class2/test.cpp b/test/ASTMerge/class2/test.cpp
new file mode 100644
index 0000000000..6021403d72
--- /dev/null
+++ b/test/ASTMerge/class2/test.cpp
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++1z -emit-pch -o %t.1.ast %S/Inputs/class3.cpp
+// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++1z -ast-merge %t.1.ast -fsyntax-only -verify %s
+// expected-no-diagnostics
+
+class C3 {
+ int method_1(C2 *x) {
+ return x->x;
+ }
+};
diff --git a/test/ASTMerge/codegen-body/Inputs/body1.c b/test/ASTMerge/codegen-body/Inputs/body1.c
new file mode 100644
index 0000000000..d4d1e4b937
--- /dev/null
+++ b/test/ASTMerge/codegen-body/Inputs/body1.c
@@ -0,0 +1,6 @@
+int f();
+
+int main()
+{
+ return f();
+}
diff --git a/test/ASTMerge/codegen-body/Inputs/body2.c b/test/ASTMerge/codegen-body/Inputs/body2.c
new file mode 100644
index 0000000000..73cb1edf99
--- /dev/null
+++ b/test/ASTMerge/codegen-body/Inputs/body2.c
@@ -0,0 +1,4 @@
+__inline__ __attribute__ ((always_inline)) int f()
+{
+ return 2;
+}
diff --git a/test/ASTMerge/codegen-body/test.c b/test/ASTMerge/codegen-body/test.c
new file mode 100644
index 0000000000..7232bf4164
--- /dev/null
+++ b/test/ASTMerge/codegen-body/test.c
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 -emit-pch -o %t.1.ast %S/Inputs/body1.c
+// RUN: %clang_cc1 -emit-pch -o %t.2.ast %S/Inputs/body2.c
+// RUN: %clang_cc1 -emit-obj -o /dev/null -ast-merge %t.1.ast -ast-merge %t.2.ast %s
+// expected-no-diagnostics
+
diff --git a/test/ASTMerge/codegen-exprs/Inputs/exprs1.c b/test/ASTMerge/codegen-exprs/Inputs/exprs1.c
new file mode 100644
index 0000000000..1c268da15f
--- /dev/null
+++ b/test/ASTMerge/codegen-exprs/Inputs/exprs1.c
@@ -0,0 +1,10 @@
+// Matching
+enum E0 {
+ E0_Val0 = 'a',
+ E0_Val1 = (17),
+ E0_Val2 = (1 << 2),
+ E0_Val3 = E0_Val2,
+ E0_Val4 = sizeof(int*),
+ E0_Val5 = (unsigned int)-1
+};
+
diff --git a/test/ASTMerge/codegen-exprs/Inputs/exprs2.c b/test/ASTMerge/codegen-exprs/Inputs/exprs2.c
new file mode 100644
index 0000000000..1c268da15f
--- /dev/null
+++ b/test/ASTMerge/codegen-exprs/Inputs/exprs2.c
@@ -0,0 +1,10 @@
+// Matching
+enum E0 {
+ E0_Val0 = 'a',
+ E0_Val1 = (17),
+ E0_Val2 = (1 << 2),
+ E0_Val3 = E0_Val2,
+ E0_Val4 = sizeof(int*),
+ E0_Val5 = (unsigned int)-1
+};
+
diff --git a/test/ASTMerge/codegen-exprs/test.c b/test/ASTMerge/codegen-exprs/test.c
new file mode 100644
index 0000000000..b5069f993b
--- /dev/null
+++ b/test/ASTMerge/codegen-exprs/test.c
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-pch -o %t.1.ast %S/Inputs/exprs1.c
+// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-pch -o %t.2.ast %S/Inputs/exprs2.c
+// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-obj -o /dev/null -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only -verify %s
+// expected-no-diagnostics
+
diff --git a/test/ASTMerge/enum/Inputs/enum1.c b/test/ASTMerge/enum/Inputs/enum1.c
new file mode 100644
index 0000000000..f2b9c5c98f
--- /dev/null
+++ b/test/ASTMerge/enum/Inputs/enum1.c
@@ -0,0 +1,42 @@
+// Matching
+enum E1 {
+ E1Enumerator1,
+ E1Enumerator2 = 3,
+ E1Enumerator3
+} x1;
+
+// Value mismatch
+enum E2 {
+ E2Enumerator1,
+ E2Enumerator2 = 3,
+ E2Enumerator3
+} x2;
+
+// Name mismatch
+enum E3 {
+ E3Enumerator1,
+ E3Enumerator2 = 3,
+ E3Enumerator3
+} x3;
+
+// Missing enumerator
+enum E4 {
+ E4Enumerator1,
+ E4Enumerator2,
+ E4Enumerator3
+} x4;
+
+// Extra enumerator
+enum E5 {
+ E5Enumerator1,
+ E5Enumerator2,
+ E5Enumerator3
+} x5;
+
+// Matching, with typedef
+typedef enum {
+ E6Enumerator1,
+ E6Enumerator2
+} E6;
+
+E6 x6;
diff --git a/test/ASTMerge/enum/Inputs/enum2.c b/test/ASTMerge/enum/Inputs/enum2.c
new file mode 100644
index 0000000000..315b4dcb6e
--- /dev/null
+++ b/test/ASTMerge/enum/Inputs/enum2.c
@@ -0,0 +1,42 @@
+// Matching
+enum E1 {
+ E1Enumerator1,
+ E1Enumerator2 = 3,
+ E1Enumerator3
+} x1;
+
+// Value mismatch
+enum E2 {
+ E2Enumerator1,
+ E2Enumerator2 = 4,
+ E2Enumerator3
+} x2;
+
+// Name mismatch
+enum E3 {
+ E3Enumerator1,
+ E3Enumerator = 3,
+ E3Enumerator3
+} x3;
+
+// Missing enumerator
+enum E4 {
+ E4Enumerator1,
+ E4Enumerator2
+} x4;
+
+// Extra enumerator
+enum E5 {
+ E5Enumerator1,
+ E5Enumerator2,
+ E5Enumerator3,
+ E5Enumerator4
+} x5;
+
+// Matching, with typedef
+typedef enum {
+ E6Enumerator1,
+ E6Enumerator2
+} E6;
+
+E6 x6;
diff --git a/test/ASTMerge/enum/test.c b/test/ASTMerge/enum/test.c
new file mode 100644
index 0000000000..57f9278757
--- /dev/null
+++ b/test/ASTMerge/enum/test.c
@@ -0,0 +1,27 @@
+// FIXME: Errors are now warnings.
+// XFAIL: *
+// RUN: %clang_cc1 -emit-pch -o %t.1.ast %S/Inputs/enum1.c
+// RUN: %clang_cc1 -emit-pch -o %t.2.ast %S/Inputs/enum2.c
+// RUN: not %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1 | FileCheck %s
+
+// CHECK: enum1.c:9:6: warning: type 'enum E2' has incompatible definitions in different translation units
+// CHECK: enum1.c:11:3: note: enumerator 'E2Enumerator2' with value 3 here
+// CHECK: enum2.c:11:3: note: enumerator 'E2Enumerator2' with value 4 here
+// CHECK: enum2.c:13:3: error: external variable 'x2' declared with incompatible types in different translation units ('enum E2' vs. 'enum E2')
+// CHECK: enum1.c:13:3: note: declared here with type 'enum E2'
+// CHECK: enum1.c:16:6: warning: type 'enum E3' has incompatible definitions in different translation units
+// CHECK: enum1.c:18:3: note: enumerator 'E3Enumerator2' with value 3 here
+// CHECK: enum2.c:18:3: note: enumerator 'E3Enumerator' with value 3 here
+// CHECK: enum2.c:20:3: error: external variable 'x3' declared with incompatible types in different translation units ('enum E3' vs. 'enum E3')
+// CHECK: enum1.c:20:3: note: declared here with type 'enum E3'
+// CHECK: enum1.c:23:6: warning: type 'enum E4' has incompatible definitions in different translation units
+// CHECK: enum1.c:26:3: note: enumerator 'E4Enumerator3' with value 2 here
+// CHECK: enum2.c:23:6: note: no corresponding enumerator here
+// CHECK: enum2.c:26:3: error: external variable 'x4' declared with incompatible types in different translation units ('enum E4' vs. 'enum E4')
+// CHECK: enum1.c:27:3: note: declared here with type 'enum E4'
+// CHECK: enum1.c:30:6: warning: type 'enum E5' has incompatible definitions in different translation units
+// CHECK: enum2.c:33:3: note: enumerator 'E5Enumerator4' with value 3 here
+// CHECK: enum1.c:30:6: note: no corresponding enumerator here
+// CHECK: enum2.c:34:3: error: external variable 'x5' declared with incompatible types in different translation units ('enum E5' vs. 'enum E5')
+// CHECK: enum1.c:34:3: note: declared here with type 'enum E5'
+// CHECK: 4 warnings and 4 errors generated
diff --git a/test/ASTMerge/exprs-cpp/Inputs/exprs3.cpp b/test/ASTMerge/exprs-cpp/Inputs/exprs3.cpp
new file mode 100644
index 0000000000..6fdc33fb39
--- /dev/null
+++ b/test/ASTMerge/exprs-cpp/Inputs/exprs3.cpp
@@ -0,0 +1,141 @@
+// Integer literals
+const char Ch1 = 'a';
+const signed char Ch2 = 'b';
+const unsigned char Ch3 = 'c';
+
+const wchar_t Ch4 = L'd';
+const signed wchar_t Ch5 = L'e';
+const unsigned wchar_t Ch6 = L'f';
+
+const short C1 = 12;
+const unsigned short C2 = 13;
+
+const int C3 = 12;
+const unsigned int C4 = 13;
+
+const long C5 = 22;
+const unsigned long C6 = 23;
+
+const long long C7 = 66;
+const unsigned long long C8 = 67;
+
+
+// String literals
+const char str1[] = "ABCD";
+const char str2[] = "ABCD" "0123";
+
+const wchar_t wstr1[] = L"DEF";
+const wchar_t wstr2[] = L"DEF" L"123";
+
+
+// Boolean literals
+const bool bval1 = true;
+const bool bval2 = false;
+
+// Floating Literals
+const float F1 = 12.2F;
+const double F2 = 1E4;
+const long double F3 = 1.2E-3L;
+
+
+// nullptr literal
+const void *vptr = nullptr;
+
+
+int glb_1[4] = { 10, 20, 30, 40 };
+
+struct S1 {
+ int a;
+ int b[3];
+};
+
+struct S2 {
+ int c;
+ S1 d;
+};
+
+S2 glb_2 = { 22, .d.a = 44, .d.b[0] = 55, .d.b[1] = 66 };
+
+void testNewThrowDelete() {
+ throw;
+ char *p = new char[10];
+ delete[] p;
+}
+
+int testArrayElement(int *x, int n) {
+ return x[n];
+}
+
+int testTernaryOp(int c, int x, int y) {
+ return c ? x : y;
+}
+
+S1 &testConstCast(const S1 &x) {
+ return const_cast<S1&>(x);
+}
+
+S1 &testStaticCast(S1 &x) {
+ return static_cast<S1&>(x);
+}
+
+S1 &testReinterpretCast(S1 &x) {
+ return reinterpret_cast<S1&>(x);
+}
+
+S1 &testDynamicCast(S1 &x) {
+ return dynamic_cast<S1&>(x);
+}
+
+int testScalarInit(int x) {
+ return int(x);
+}
+
+struct S {
+ float f;
+ double d;
+};
+struct T {
+ int i;
+ struct S s[10];
+};
+
+void testOffsetOf() {
+ __builtin_offsetof(struct T, s[2].d);
+}
+
+
+int testDefaultArg(int a = 2*2) {
+ return a;
+}
+
+int testDefaultArgExpr() {
+ return testDefaultArg();
+}
+
+template <typename T> // T has TemplateTypeParmType
+void testTemplateTypeParmType(int i);
+
+void useTemplateType() {
+ testTemplateTypeParmType<char>(4);
+}
+
+const bool ExpressionTrait = __is_lvalue_expr(1);
+const unsigned ArrayRank = __array_rank(int[10][20]);
+const unsigned ArrayExtent = __array_extent(int[10][20], 1);
+
+constexpr int testLambdaAdd(int toAdd) {
+ const int Captured1 = 1, Captured2 = 2;
+ constexpr auto LambdaAdd = [Captured1, Captured2](int k) -> int {
+ return Captured1 + Captured2 + k;
+ };
+ return LambdaAdd(toAdd);
+}
+
+template<typename T>
+struct TestLambdaTemplate {
+ T i, j;
+ TestLambdaTemplate(T i, const T &j) : i(i), j(j) {}
+ T testLambda(T k) {
+ return [this](T k) -> decltype(auto) { return i + j + k; }(k);
+ }
+};
diff --git a/test/ASTMerge/exprs-cpp/test.cpp b/test/ASTMerge/exprs-cpp/test.cpp
new file mode 100644
index 0000000000..c0b282ec02
--- /dev/null
+++ b/test/ASTMerge/exprs-cpp/test.cpp
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++1z -fcxx-exceptions -emit-pch -o %t.1.ast %S/Inputs/exprs3.cpp
+// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++1z -fcxx-exceptions -ast-merge %t.1.ast -fsyntax-only -verify %s
+// expected-no-diagnostics
+
+static_assert(Ch1 == 'a');
+static_assert(Ch2 == 'b');
+static_assert(Ch3 == 'c');
+
+static_assert(Ch4 == L'd');
+static_assert(Ch5 == L'e');
+static_assert(Ch6 == L'f');
+
+static_assert(C1 == 12);
+static_assert(C2 == 13);
+
+static_assert(C3 == 12);
+static_assert(C4 == 13);
+
+static_assert(C5 == 22L);
+static_assert(C6 == 23L);
+
+static_assert(C7 == 66LL);
+static_assert(C8 == 67ULL);
+
+static_assert(bval1 == true);
+static_assert(bval2 == false);
+
+static_assert(ExpressionTrait == false);
+
+static_assert(ArrayRank == 2);
+static_assert(ArrayExtent == 20);
+
+static_assert(testLambdaAdd(3) == 6);
+
+void testImport(int *x, const S1 &cs1, S1 &s1) {
+ testNewThrowDelete();
+ testArrayElement(nullptr, 12);
+ testTernaryOp(0, 1, 2);
+ testConstCast(cs1);
+ testStaticCast(s1);
+ testReinterpretCast(s1);
+ testDynamicCast(s1);
+ testScalarInit(42);
+ testOffsetOf();
+ testDefaultArg(12);
+ testDefaultArg();
+ testDefaultArgExpr();
+ useTemplateType();
+ TestLambdaTemplate<int>(1, 2).testLambda(3);
+}
diff --git a/test/ASTMerge/exprs/Inputs/exprs1.c b/test/ASTMerge/exprs/Inputs/exprs1.c
new file mode 100644
index 0000000000..1c268da15f
--- /dev/null
+++ b/test/ASTMerge/exprs/Inputs/exprs1.c
@@ -0,0 +1,10 @@
+// Matching
+enum E0 {
+ E0_Val0 = 'a',
+ E0_Val1 = (17),
+ E0_Val2 = (1 << 2),
+ E0_Val3 = E0_Val2,
+ E0_Val4 = sizeof(int*),
+ E0_Val5 = (unsigned int)-1
+};
+
diff --git a/test/ASTMerge/exprs/Inputs/exprs2.c b/test/ASTMerge/exprs/Inputs/exprs2.c
new file mode 100644
index 0000000000..1c268da15f
--- /dev/null
+++ b/test/ASTMerge/exprs/Inputs/exprs2.c
@@ -0,0 +1,10 @@
+// Matching
+enum E0 {
+ E0_Val0 = 'a',
+ E0_Val1 = (17),
+ E0_Val2 = (1 << 2),
+ E0_Val3 = E0_Val2,
+ E0_Val4 = sizeof(int*),
+ E0_Val5 = (unsigned int)-1
+};
+
diff --git a/test/ASTMerge/exprs/test.c b/test/ASTMerge/exprs/test.c
new file mode 100644
index 0000000000..7495bb6a87
--- /dev/null
+++ b/test/ASTMerge/exprs/test.c
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-pch -o %t.1.ast %S/Inputs/exprs1.c
+// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-pch -o %t.2.ast %S/Inputs/exprs2.c
+// RUN: %clang_cc1 -triple %itanium_abi_triple -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only -verify %s
+// expected-no-diagnostics
+
diff --git a/test/ASTMerge/function-cpp/Inputs/function-1.cpp b/test/ASTMerge/function-cpp/Inputs/function-1.cpp
new file mode 100644
index 0000000000..ee97a1a8a5
--- /dev/null
+++ b/test/ASTMerge/function-cpp/Inputs/function-1.cpp
@@ -0,0 +1,8 @@
+
+template<typename T> constexpr T add(T arg1, T arg2) {
+ return arg1 + arg2;
+}
+
+template<> constexpr int add(int arg1, int arg2) {
+ return arg1 + arg2 + 2;
+}
diff --git a/test/ASTMerge/function-cpp/test.cpp b/test/ASTMerge/function-cpp/test.cpp
new file mode 100644
index 0000000000..304ce3c634
--- /dev/null
+++ b/test/ASTMerge/function-cpp/test.cpp
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -std=c++1z -emit-pch -o %t.1.ast %S/Inputs/function-1.cpp
+// RUN: %clang_cc1 -std=c++1z -ast-merge %t.1.ast -fsyntax-only %s 2>&1 | FileCheck %s
+// XFAIL: *
+
+static_assert(add(1, 2) == 5);
+
+// FIXME: support of templated function overload is still not implemented.
+static_assert(add('\1', '\2') == 3);
+
+// CHECK-NOT: static_assert
diff --git a/test/ASTMerge/function/Inputs/function1.c b/test/ASTMerge/function/Inputs/function1.c
new file mode 100644
index 0000000000..4523bd3d79
--- /dev/null
+++ b/test/ASTMerge/function/Inputs/function1.c
@@ -0,0 +1,6 @@
+void f0(int);
+void f1(int, float);
+void f2();
+void f3(void);
+void f4(int, int);
+int f5(int) __attribute__((const));
diff --git a/test/ASTMerge/function/Inputs/function2.c b/test/ASTMerge/function/Inputs/function2.c
new file mode 100644
index 0000000000..6ca810a6f2
--- /dev/null
+++ b/test/ASTMerge/function/Inputs/function2.c
@@ -0,0 +1,7 @@
+typedef int Int;
+void f0(Int);
+void f1(Int, double);
+void f2(int, int);
+void f3(int);
+static void f4(float, float);
+int f5(int) __attribute__((const));
diff --git a/test/ASTMerge/function/test.c b/test/ASTMerge/function/test.c
new file mode 100644
index 0000000000..8d4d0c15f2
--- /dev/null
+++ b/test/ASTMerge/function/test.c
@@ -0,0 +1,17 @@
+// FIXME: Errors are now warnings.
+// XFAIL: *
+// RUN: %clang_cc1 -emit-pch -o %t.1.ast %S/Inputs/function1.c
+// RUN: %clang_cc1 -emit-pch -o %t.2.ast %S/Inputs/function2.c
+// RUN: not %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1 | FileCheck %s
+// RUN: %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only -verify %s
+
+// CHECK: function2.c:3:6: error: external function 'f1' declared with incompatible types in different translation units ('void (Int, double)' (aka 'void (int, double)') vs. 'void (int, float)')
+// CHECK: function1.c:2:6: note: declared here with type 'void (int, float)'
+// CHECK: function2.c:5:6: error: external function 'f3' declared with incompatible types in different translation units ('void (int)' vs. 'void (void)')
+// CHECK: function1.c:4:6: note: declared here with type 'void (void)'
+// CHECK: 2 errors generated
+
+// expected-error@Inputs/function2.c:3 {{external function 'f1' declared with incompatible types}}
+// expected-note@Inputs/function1.c:2 {{declared here}}
+// expected-error@Inputs/function2.c:5 {{external function 'f3' declared with incompatible types}}
+// expected-note@Inputs/function1.c:4 {{declared here}}
diff --git a/test/ASTMerge/inheritance/Inputs/inheritance-base.cpp b/test/ASTMerge/inheritance/Inputs/inheritance-base.cpp
new file mode 100644
index 0000000000..26fe42eb64
--- /dev/null
+++ b/test/ASTMerge/inheritance/Inputs/inheritance-base.cpp
@@ -0,0 +1,7 @@
+class A
+{
+public:
+ int x;
+ A(int _x) : x(_x) {
+ }
+};
diff --git a/test/ASTMerge/inheritance/test.cpp b/test/ASTMerge/inheritance/test.cpp
new file mode 100644
index 0000000000..7fce82a736
--- /dev/null
+++ b/test/ASTMerge/inheritance/test.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++1z -emit-pch -o %t.1.ast %S/Inputs/inheritance-base.cpp
+// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++1z -ast-merge %t.1.ast -fsyntax-only -verify %s
+// expected-no-diagnostics
+
+class B : public A {
+ B(int _a) : A(_a) {
+ }
+};
diff --git a/test/ASTMerge/init-ctors/Inputs/init-ctors-classes.cpp b/test/ASTMerge/init-ctors/Inputs/init-ctors-classes.cpp
new file mode 100644
index 0000000000..fd51f86063
--- /dev/null
+++ b/test/ASTMerge/init-ctors/Inputs/init-ctors-classes.cpp
@@ -0,0 +1,19 @@
+class A_base
+{
+public:
+ int x;
+ A_base() : x(0) {
+ }
+ A_base(int _x) : x(static_cast<int>(_x)) {
+ }
+};
+
+class A : public A_base
+{
+public:
+ int y;
+ struct { int z; };
+ int array[2];
+ A(int _x) : A_base(_x), y(0), z(1), array{{2},{3}} {
+ }
+};
diff --git a/test/ASTMerge/init-ctors/test.cpp b/test/ASTMerge/init-ctors/test.cpp
new file mode 100644
index 0000000000..5f0ba4decd
--- /dev/null
+++ b/test/ASTMerge/init-ctors/test.cpp
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++1z -emit-pch -o %t.1.ast %S/Inputs/init-ctors-classes.cpp
+// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++1z -ast-merge %t.1.ast -fsyntax-only -verify %s
+// expected-no-diagnostics
+
+class B {
+ int method_1() {
+ A a(0);
+ return a.x;
+ }
+};
diff --git a/test/ASTMerge/injected-class-name-decl/Inputs/inject1.cpp b/test/ASTMerge/injected-class-name-decl/Inputs/inject1.cpp
new file mode 100644
index 0000000000..f6f769746d
--- /dev/null
+++ b/test/ASTMerge/injected-class-name-decl/Inputs/inject1.cpp
@@ -0,0 +1,2 @@
+template <class X>
+class C { static X x; };
diff --git a/test/ASTMerge/injected-class-name-decl/Inputs/inject2.cpp b/test/ASTMerge/injected-class-name-decl/Inputs/inject2.cpp
new file mode 100644
index 0000000000..7cf5fc2232
--- /dev/null
+++ b/test/ASTMerge/injected-class-name-decl/Inputs/inject2.cpp
@@ -0,0 +1,2 @@
+template <class X>
+X C<X>::x;
diff --git a/test/ASTMerge/injected-class-name-decl/test.cpp b/test/ASTMerge/injected-class-name-decl/test.cpp
new file mode 100644
index 0000000000..9f31674108
--- /dev/null
+++ b/test/ASTMerge/injected-class-name-decl/test.cpp
@@ -0,0 +1,3 @@
+// RUN: %clang_cc1 -std=c++1z -emit-pch -o %t.ast %S/Inputs/inject1.cpp
+// RUN: %clang_cc1 -std=c++1z -emit-obj -o /dev/null -ast-merge %t.ast %S/Inputs/inject2.cpp
+// expected-no-diagnostics
diff --git a/test/ASTMerge/interface/Inputs/interface1.m b/test/ASTMerge/interface/Inputs/interface1.m
new file mode 100644
index 0000000000..6192150089
--- /dev/null
+++ b/test/ASTMerge/interface/Inputs/interface1.m
@@ -0,0 +1,105 @@
+// Matches
+@interface I1 {
+ int ivar1;
+}
+@end
+
+// Matches
+@interface I2 : I1 {
+ float ivar2;
+}
+@end
+
+// Ivar mismatch
+@interface I3 {
+ int ivar1;
+ int ivar2;
+}
+@end
+
+// Superclass mismatch
+@interface I4 : I2 {
+}
+@end
+
+// Methods match
+@interface I5
+- (int)foo;
++ (float)bar;
+@end
+
+// Method mismatch
+@interface I6
+- (int)foo;
++ (int)foo;
+@end
+
+// Method mismatch
+@interface I7
+- (int)foo;
++ (int)bar:(int)x;
+@end
+
+// Method mismatch
+@interface I8
+- (int)foo;
++ (int)bar:(float)x;
+@end
+
+// Matching protocol
+@protocol P0
++ (int)foo;
+- (int)bar:(float)x;
+@end
+
+// Protocol with mismatching method
+@protocol P1
++ (int)foo;
+- (int)bar:(float)x;
+@end
+
+// Interface with protocol
+@interface I9 <P0>
++ (int)foo;
+- (int)bar:(float)x;
+@end
+
+// Protocol with protocol
+@protocol P2 <P0>
+- (float)wibble:(int)a1 second:(int)a2;
+@end
+
+// Forward-declared interfaces
+@class I10, I11;
+@interface I12
+@end
+
+// Forward-declared protocols
+@protocol P3, P5;
+@protocol P4
+- (double)honk:(int)a;
+@end
+
+// Interface with implementation
+@interface I13
+@end
+
+@implementation I13
+@end
+
+@interface I13a
+@end
+
+@implementation I13a
+@end
+
+// Implementation by itself
+@implementation I14 : I12
+@end
+
+@implementation I15 : I12
+@end
+
+@interface ImportSelectorSLoc { }
+-(int)addInt:(int)a toInt:(int)b moduloInt:(int)c; // don't crash here
+@end
diff --git a/test/ASTMerge/interface/Inputs/interface2.m b/test/ASTMerge/interface/Inputs/interface2.m
new file mode 100644
index 0000000000..2133bd1381
--- /dev/null
+++ b/test/ASTMerge/interface/Inputs/interface2.m
@@ -0,0 +1,100 @@
+// Matches
+@interface I1 {
+ int ivar1;
+}
+@end
+
+// Matches
+@interface I2 : I1 {
+ float ivar2;
+}
+@end
+
+// Ivar mismatch
+@interface I3 {
+ int ivar1;
+ float ivar2;
+}
+@end
+
+// Superclass mismatch
+@interface I4 : I1 {
+}
+@end
+
+// Methods match
+@interface I5
++ (float)bar;
+- (int)foo;
+@end
+
+// Method mismatch
+@interface I6
++ (float)foo;
+@end
+
+// Method mismatch
+@interface I7
+- (int)foo;
++ (int)bar:(float)x;
+@end
+
+// Method mismatch
+@interface I8
+- (int)foo;
++ (int)bar:(float)x, ...;
+@end
+
+// Matching protocol
+@protocol P0
++ (int)foo;
+- (int)bar:(float)x;
+@end
+
+// Protocol with mismatching method
+@protocol P1
++ (int)foo;
+- (int)bar:(double)x;
+@end
+
+// Interface with protocol
+@interface I9 <P0>
++ (int)foo;
+- (int)bar:(float)x;
+@end
+
+// Protocol with protocol
+@protocol P2 <P0>
+- (float)wibble:(int)a1 second:(int)a2;
+@end
+
+// Forward-declared interface
+@class I10; @interface I12 @end
+@interface I11
+@end
+
+// Forward-declared protocols
+@protocol P3, P4;
+@protocol P5
+- (double)honk:(int)a;
+@end
+
+// Interface with implementation
+@interface I13
+@end
+
+@implementation I13
+@end
+
+@interface I13b
+@end
+
+@implementation I13b
+@end
+
+// Implementation by itself
+@implementation I14 : I12
+@end
+
+@implementation I15 : I11
+@end
diff --git a/test/ASTMerge/interface/test.m b/test/ASTMerge/interface/test.m
new file mode 100644
index 0000000000..7338e903f1
--- /dev/null
+++ b/test/ASTMerge/interface/test.m
@@ -0,0 +1,24 @@
+// FIXME: Errors are now warnings.
+// XFAIL: *
+// RUN: %clang_cc1 -emit-pch -o %t.1.ast %S/Inputs/interface1.m
+// RUN: %clang_cc1 -emit-pch -o %t.2.ast %S/Inputs/interface2.m
+// RUN: not %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1 | FileCheck %s
+
+// CHECK: interface2.m:16:9: error: instance variable 'ivar2' declared with incompatible types in different translation units ('float' vs. 'int')
+// CHECK: interface1.m:16:7: note: declared here with type 'int'
+// CHECK: interface1.m:21:12: error: class 'I4' has incompatible superclasses
+// CHECK: interface1.m:21:17: note: inherits from superclass 'I2' here
+// CHECK: interface2.m:21:17: note: inherits from superclass 'I1' here
+// CHECK: interface2.m:33:1: error: class method 'foo' has incompatible result types in different translation units ('float' vs. 'int')
+// CHECK: interface1.m:34:1: note: class method 'foo' also declared here
+// CHECK: interface2.m:39:19: error: class method 'bar:' has a parameter with a different types in different translation units ('float' vs. 'int')
+// CHECK: interface1.m:40:17: note: declared here with type 'int'
+// CHECK: interface2.m:45:1: error: class method 'bar:' is variadic in one translation unit and not variadic in another
+// CHECK: interface1.m:46:1: note: class method 'bar:' also declared here
+// CHECK: interface2.m:57:20: error: instance method 'bar:' has a parameter with a different types in different translation units ('double' vs. 'float')
+// CHECK: interface1.m:58:19: note: declared here with type 'float'
+// CHECK: interface1.m:100:17: error: class 'I15' has incompatible superclasses
+// CHECK: interface1.m:100:17: note: inherits from superclass 'I12' here
+// CHECK: interface2.m:99:17: note: inherits from superclass 'I11' here
+// CHECK: 8 errors generated
+
diff --git a/test/ASTMerge/macro/Inputs/macro.modulemap b/test/ASTMerge/macro/Inputs/macro.modulemap
new file mode 100644
index 0000000000..dba1f2207f
--- /dev/null
+++ b/test/ASTMerge/macro/Inputs/macro.modulemap
@@ -0,0 +1,4 @@
+module macro1 [extern_c] {
+ header "macro1.h"
+ export *
+}
diff --git a/test/ASTMerge/macro/Inputs/macro1.h b/test/ASTMerge/macro/Inputs/macro1.h
new file mode 100644
index 0000000000..9613394967
--- /dev/null
+++ b/test/ASTMerge/macro/Inputs/macro1.h
@@ -0,0 +1,5 @@
+typedef void *VoidRef;
+
+void maybeNull(
+ int i,
+ _Nullable VoidRef *_Nullable);
diff --git a/test/ASTMerge/macro/Inputs/macro1.m b/test/ASTMerge/macro/Inputs/macro1.m
new file mode 100644
index 0000000000..2612613bd0
--- /dev/null
+++ b/test/ASTMerge/macro/Inputs/macro1.m
@@ -0,0 +1,5 @@
+@import macro1;
+
+void foo() {
+ maybeNull(0, 0);
+}
diff --git a/test/ASTMerge/macro/Inputs/macro2.m b/test/ASTMerge/macro/Inputs/macro2.m
new file mode 100644
index 0000000000..b5b155a95b
--- /dev/null
+++ b/test/ASTMerge/macro/Inputs/macro2.m
@@ -0,0 +1,5 @@
+void foo();
+
+void bar() {
+ foo();
+}
diff --git a/test/ASTMerge/macro/test.m b/test/ASTMerge/macro/test.m
new file mode 100644
index 0000000000..77e596d3ba
--- /dev/null
+++ b/test/ASTMerge/macro/test.m
@@ -0,0 +1,6 @@
+// RUN: rm -rf %t
+// RUN: mkdir -p %t/cache
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t/cache -fmodule-map-file=%S/Inputs/macro.modulemap -I%S/Inputs -emit-pch -o %t.1.ast %S/Inputs/macro1.m
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t/cache -fmodule-map-file=%S/Inputs/macro.modulemap -I%S/Inputs -emit-pch -o %t.2.ast %S/Inputs/macro2.m
+// RUN: %clang_cc1 -fmodules -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only -verify %s
+// expected-no-diagnostics
diff --git a/test/ASTMerge/namespace/Inputs/namespace1.cpp b/test/ASTMerge/namespace/Inputs/namespace1.cpp
new file mode 100644
index 0000000000..4a539523aa
--- /dev/null
+++ b/test/ASTMerge/namespace/Inputs/namespace1.cpp
@@ -0,0 +1,27 @@
+// Merge success
+namespace N1 {
+ int x;
+}
+
+// Merge multiple namespaces
+namespace N2 {
+ extern int x;
+}
+namespace N2 {
+ extern float y;
+}
+
+// Merge namespace with conflict
+namespace N3 {
+ extern float z;
+}
+
+namespace AliasWithSameName = N3;
+
+namespace TestUnresolvedTypenameAndValueDecls {
+template <class T> class Base {
+public:
+ typedef T foo;
+ void bar();
+};
+}
diff --git a/test/ASTMerge/namespace/Inputs/namespace2.cpp b/test/ASTMerge/namespace/Inputs/namespace2.cpp
new file mode 100644
index 0000000000..f65057d1ca
--- /dev/null
+++ b/test/ASTMerge/namespace/Inputs/namespace2.cpp
@@ -0,0 +1,60 @@
+// Merge success
+namespace N1 {
+ extern int x0;
+}
+
+// Merge multiple namespaces
+namespace N2 {
+ extern int x;
+}
+namespace N2 {
+ extern float y;
+}
+
+// Merge namespace with conflict
+namespace N3 {
+ extern double z;
+}
+
+namespace Enclosing {
+namespace Nested {
+ const int z = 4;
+}
+}
+
+namespace ContainsInline {
+ inline namespace Inline {
+ const int z = 10;
+ }
+}
+
+namespace TestAliasName = Enclosing::Nested;
+// NOTE: There is no warning on this alias.
+namespace AliasWithSameName = Enclosing::Nested;
+
+namespace TestUsingDecls {
+
+namespace A {
+void foo();
+}
+namespace B {
+using A::foo; // <- a UsingDecl creating a UsingShadow
+}
+
+}// end namespace TestUsingDecls
+
+namespace TestUnresolvedTypenameAndValueDecls {
+
+template <class T> class Base;
+template <class T> class Derived : public Base<T> {
+public:
+ using typename Base<T>::foo;
+ using Base<T>::bar;
+ typedef typename Derived::foo NewUnresolvedUsingType;
+};
+
+} // end namespace TestUnresolvedTypenameAndValueDecls
+
+namespace TestUsingNamespace {
+ using namespace Enclosing;
+}
diff --git a/test/ASTMerge/namespace/test.cpp b/test/ASTMerge/namespace/test.cpp
new file mode 100644
index 0000000000..f0f8b73ffc
--- /dev/null
+++ b/test/ASTMerge/namespace/test.cpp
@@ -0,0 +1,19 @@
+// FIXME: Errors are now warnings.
+// XFAIL: *
+// RUN: %clang_cc1 -emit-pch -std=c++1z -o %t.1.ast %S/Inputs/namespace1.cpp
+// RUN: %clang_cc1 -emit-pch -std=c++1z -o %t.2.ast %S/Inputs/namespace2.cpp
+// RUN: not %clang_cc1 -std=c++1z -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1 | FileCheck %s
+
+static_assert(TestAliasName::z == 4);
+static_assert(ContainsInline::z == 10);
+
+void testImport() {
+ typedef TestUnresolvedTypenameAndValueDecls::Derived<int> Imported;
+ Imported a; // Successful instantiation
+ static_assert(sizeof(Imported::foo) == sizeof(int));
+ static_assert(sizeof(TestUnresolvedTypenameAndValueDecls::Derived<double>::NewUnresolvedUsingType) == sizeof(double));
+}
+
+
+// CHECK: namespace2.cpp:16:17: error: external variable 'z' declared with incompatible types in different translation units ('double' vs. 'float')
+// CHECK: namespace1.cpp:16:16: note: declared here with type 'float'
diff --git a/test/ASTMerge/property/Inputs/property1.m b/test/ASTMerge/property/Inputs/property1.m
new file mode 100644
index 0000000000..22fe0a0222
--- /dev/null
+++ b/test/ASTMerge/property/Inputs/property1.m
@@ -0,0 +1,31 @@
+// Matching properties
+@interface I1 {
+}
+- (int)getProp2;
+- (void)setProp2:(int)value;
+@end
+
+// Mismatched property
+@interface I2
+@property (readonly) float Prop1;
+@end
+
+// Properties with implementations
+@interface I3 {
+ int ivar1;
+ int ivar2;
+ int ivar3;
+ int Prop4;
+}
+@property int Prop1;
+@property int Prop2;
+@property int Prop3;
+@property int Prop4;
+@end
+
+@implementation I3
+@synthesize Prop1 = ivar1;
+@synthesize Prop2 = ivar3;
+@dynamic Prop3;
+@synthesize Prop4;
+@end
diff --git a/test/ASTMerge/property/Inputs/property2.m b/test/ASTMerge/property/Inputs/property2.m
new file mode 100644
index 0000000000..64a03fb04e
--- /dev/null
+++ b/test/ASTMerge/property/Inputs/property2.m
@@ -0,0 +1,33 @@
+// Matching properties
+@interface I1 {
+}
+- (int)getProp2;
+- (void)setProp2:(int)value;
+@property (readonly) int Prop1;
+@property (getter = getProp2, setter = setProp2:) int Prop2;
+@end
+
+// Mismatched property
+@interface I2
+@property (readonly) int Prop1;
+@end
+
+// Properties with implementations
+@interface I3 {
+ int ivar1;
+ int ivar2;
+ int ivar3;
+ int Prop4;
+}
+@property int Prop1;
+@property int Prop2;
+@property int Prop3;
+@property int Prop4;
+@end
+
+@implementation I3
+@synthesize Prop2 = ivar2;
+@synthesize Prop1 = ivar1;
+@synthesize Prop3 = ivar3;
+@synthesize Prop4 = Prop4;
+@end
diff --git a/test/ASTMerge/property/test.m b/test/ASTMerge/property/test.m
new file mode 100644
index 0000000000..e48d54ed08
--- /dev/null
+++ b/test/ASTMerge/property/test.m
@@ -0,0 +1,15 @@
+// FIXME: Errors are now warnings.
+// XFAIL: *
+// RUN: %clang_cc1 -emit-pch -o %t.1.ast %S/Inputs/property1.m
+// RUN: %clang_cc1 -emit-pch -o %t.2.ast %S/Inputs/property2.m
+// RUN: not %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1 | FileCheck %s
+
+// CHECK: property2.m:12:26: error: property 'Prop1' declared with incompatible types in different translation units ('int' vs. 'float')
+// CHECK: property1.m:10:28: note: declared here with type 'float'
+// CHECK: property2.m:12:26: error: instance method 'Prop1' has incompatible result types in different translation units ('int' vs. 'float')
+// CHECK: property1.m:10:28: note: instance method 'Prop1' also declared here
+// CHECK: property1.m:28:21: error: property 'Prop2' is synthesized to different ivars in different translation units ('ivar3' vs. 'ivar2')
+// CHECK: property2.m:29:21: note: property is synthesized to ivar 'ivar2' here
+// CHECK: property1.m:29:10: error: property 'Prop3' is implemented with @dynamic in one translation but @synthesize in another translation unit
+// CHECK: property2.m:31:13: note: property 'Prop3' is implemented with @synthesize here
+// CHECK: 4 errors generated.
diff --git a/test/ASTMerge/std-initializer-list/Inputs/il.cpp b/test/ASTMerge/std-initializer-list/Inputs/il.cpp
new file mode 100644
index 0000000000..3b2ac187c8
--- /dev/null
+++ b/test/ASTMerge/std-initializer-list/Inputs/il.cpp
@@ -0,0 +1,9 @@
+namespace std {
+template <typename T>
+struct initializer_list {
+ const T *begin, *end;
+ initializer_list();
+};
+} // namespace std
+
+std::initializer_list<int> IL = {1, 2, 3, 4};
diff --git a/test/ASTMerge/std-initializer-list/test.cpp b/test/ASTMerge/std-initializer-list/test.cpp
new file mode 100644
index 0000000000..ca7330d308
--- /dev/null
+++ b/test/ASTMerge/std-initializer-list/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: unsupported AST node
diff --git a/test/ASTMerge/struct/Inputs/struct1.c b/test/ASTMerge/struct/Inputs/struct1.c
new file mode 100644
index 0000000000..a85aec70a8
--- /dev/null
+++ b/test/ASTMerge/struct/Inputs/struct1.c
@@ -0,0 +1,141 @@
+typedef int Int;
+typedef float Float;
+
+// Matches
+struct S0 {
+ Int field1;
+ Float field2;
+};
+
+struct S0 x0;
+
+// Mismatch in field type
+struct S1 {
+ Int field1;
+ int field2;
+};
+
+struct S1 x1;
+
+// Mismatch in tag kind.
+struct S2 { int i; float f; } x2;
+
+// Missing fields
+struct S3 { int i; float f; double d; } x3;
+
+// Extra fields
+struct S4 { int i; } x4;
+
+// Bit-field matches
+struct S5 { int i : 8; unsigned j : 8; } x5;
+
+// Bit-field mismatch
+struct S6 { int i : 8; unsigned j : 8; } x6;
+
+// Bit-field mismatch
+struct S7 { int i : 8; unsigned j : 8; } x7;
+
+// Incomplete type
+struct S8 *x8;
+
+// Incomplete type
+struct S9 { int i; float f; } *x9;
+
+// Incomplete type
+struct S10 *x10;
+
+// Matches
+struct ListNode {
+ int value;
+ struct ListNode *Next;
+} xList;
+
+// Mismatch due to struct used internally
+struct DeepError {
+ int value;
+ struct DeeperError { int i; int f; } *Deeper;
+} xDeep;
+
+// Matches
+struct {
+ Int i;
+ float f;
+} x11;
+
+// Matches
+typedef struct {
+ Int i;
+ float f;
+} S12;
+
+S12 x12;
+
+// Mismatch
+typedef struct {
+ Float i; // Mismatch here.
+ float f;
+} S13;
+
+S13 x13;
+
+// Matches
+struct Unnamed {
+ union {
+ struct {
+ int i;
+ } S;
+ struct {
+ float i;
+ } R;
+ } U;
+} x14;
+
+// Matches
+struct DeepUnnamed {
+ union {
+ union {
+ struct {
+ long i;
+ } S;
+ struct {
+ int i;
+ } R;
+ } U1;
+ union {
+ struct {
+ long i;
+ } S;
+ struct {
+ float i;
+ } T;
+ } U2;
+ } U;
+ struct {
+ long i;
+ } V;
+} x15;
+
+// Mismatch due to unnamed struct used internally
+struct DeepUnnamedError {
+ union {
+ union {
+ struct {
+ long i;
+ } S;
+ struct {
+ int i;
+ } R;
+ } U1;
+ union {
+ struct {
+ long i; // Mismatch here.
+ } S;
+ struct {
+ float i;
+ } T;
+ } U2;
+ } U;
+ struct {
+ long i;
+ } V;
+} x16;
diff --git a/test/ASTMerge/struct/Inputs/struct2.c b/test/ASTMerge/struct/Inputs/struct2.c
new file mode 100644
index 0000000000..49fe36d823
--- /dev/null
+++ b/test/ASTMerge/struct/Inputs/struct2.c
@@ -0,0 +1,138 @@
+// Matches
+struct S0 {
+ int field1;
+ float field2;
+};
+
+struct S0 x0;
+
+// Mismatch in field type
+struct S1 {
+ int field1;
+ float field2;
+};
+
+struct S1 x1;
+
+// Mismatch in tag kind.
+union S2 { int i; float f; } x2;
+
+// Missing fields
+struct S3 { int i; float f; } x3;
+
+// Extra fields
+struct S4 { int i; float f; } x4;
+
+// Bit-field matches
+struct S5 { int i : 8; unsigned j : 8; } x5;
+
+// Bit-field mismatch
+struct S6 { int i : 8; unsigned j; } x6;
+
+// Bit-field mismatch
+struct S7 { int i : 8; unsigned j : 16; } x7;
+
+// Incomplete type
+struct S8 { int i; float f; } *x8;
+
+// Incomplete type
+struct S9 *x9;
+
+// Incomplete type
+struct S10 *x10;
+
+// Matches
+struct ListNode {
+ int value;
+ struct ListNode *Next;
+} xList;
+
+// Mismatch due to struct used internally
+struct DeepError {
+ int value;
+ struct DeeperError { int i; float f; } *Deeper;
+} xDeep;
+
+// Matches
+struct {
+ int i;
+ float f;
+} x11;
+
+// Matches
+typedef struct {
+ int i;
+ float f;
+} S12;
+
+S12 x12;
+
+// Mismatch
+typedef struct {
+ int i; // Mismatch here.
+ float f;
+} S13;
+
+S13 x13;
+
+// Matches
+struct Unnamed {
+ union {
+ struct {
+ int i;
+ } S;
+ struct {
+ float i;
+ } R;
+ } U;
+} x14;
+
+// Matches
+struct DeepUnnamed {
+ union {
+ union {
+ struct {
+ long i;
+ } S;
+ struct {
+ int i;
+ } R;
+ } U1;
+ union {
+ struct {
+ long i;
+ } S;
+ struct {
+ float i;
+ } T;
+ } U2;
+ } U;
+ struct {
+ long i;
+ } V;
+} x15;
+
+// Mismatch due to unnamed struct used internally
+struct DeepUnnamedError {
+ union {
+ union {
+ struct {
+ long i;
+ } S;
+ struct {
+ int i;
+ } R;
+ } U1;
+ union {
+ struct {
+ float i; // Mismatch here.
+ } S;
+ struct {
+ float i;
+ } T;
+ } U2;
+ } U;
+ struct {
+ long i;
+ } V;
+} x16;
diff --git a/test/ASTMerge/struct/test.c b/test/ASTMerge/struct/test.c
new file mode 100644
index 0000000000..1f5f66da3c
--- /dev/null
+++ b/test/ASTMerge/struct/test.c
@@ -0,0 +1,57 @@
+// FIXME: Errors are now warnings.
+// XFAIL: *
+// RUN: %clang_cc1 -emit-pch -o %t.1.ast %S/Inputs/struct1.c
+// RUN: %clang_cc1 -emit-pch -o %t.2.ast %S/Inputs/struct2.c
+// RUN: not %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1 | FileCheck %s
+
+// CHECK: struct1.c:13:8: warning: type 'struct S1' has incompatible definitions in different translation units
+// CHECK: struct1.c:15:7: note: field 'field2' has type 'int' here
+// CHECK: struct2.c:12:9: note: field 'field2' has type 'float' here
+// CHECK: struct2.c:15:11: error: external variable 'x1' declared with incompatible types in different translation units ('struct S1' vs. 'struct S1')
+// CHECK: struct1.c:18:11: note: declared here with type 'struct S1'
+// CHECK: struct1.c:21:8: warning: type 'struct S2' has incompatible definitions in different translation units
+// CHECK: struct2.c:18:7: note: 'S2' is a union here
+// CHECK: struct2.c:18:30: error: external variable 'x2' declared with incompatible types in different translation units ('union S2' vs. 'struct S2')
+// CHECK: struct1.c:21:31: note: declared here with type 'struct S2'
+// CHECK: struct1.c:24:8: warning: type 'struct S3' has incompatible definitions in different translation units
+// CHECK: struct1.c:24:36: note: field 'd' has type 'double' here
+// CHECK: struct2.c:21:8: note: no corresponding field here
+// CHECK: struct2.c:21:31: error: external variable 'x3' declared with incompatible types in different translation units ('struct S3' vs. 'struct S3')
+// CHECK: struct1.c:24:41: note: declared here with type 'struct S3'
+// CHECK: struct1.c:27:8: warning: type 'struct S4' has incompatible definitions in different translation units
+// CHECK: struct2.c:24:26: note: field 'f' has type 'float' here
+// CHECK: struct1.c:27:8: note: no corresponding field here
+// CHECK: struct2.c:24:31: error: external variable 'x4' declared with incompatible types in different translation units ('struct S4' vs. 'struct S4')
+// CHECK: struct1.c:27:22: note: declared here with type 'struct S4'
+// CHECK: struct1.c:33:8: warning: type 'struct S6' has incompatible definitions in different translation units
+// CHECK: struct1.c:33:33: note: bit-field 'j' with type 'unsigned int' and length 8 here
+// CHECK: struct2.c:30:33: note: field 'j' is not a bit-field
+// CHECK: struct2.c:30:38: error: external variable 'x6' declared with incompatible types in different translation units ('struct S6' vs. 'struct S6')
+// CHECK: struct1.c:33:42: note: declared here with type 'struct S6'
+// CHECK: struct1.c:36:8: warning: type 'struct S7' has incompatible definitions in different translation units
+// CHECK: struct1.c:36:33: note: bit-field 'j' with type 'unsigned int' and length 8 here
+// CHECK: struct2.c:33:33: note: bit-field 'j' with type 'unsigned int' and length 16 here
+// CHECK: struct2.c:33:43: error: external variable 'x7' declared with incompatible types in different translation units ('struct S7' vs. 'struct S7')
+// CHECK: struct1.c:36:42: note: declared here with type 'struct S7'
+// CHECK: struct1.c:56:10: warning: type 'struct DeeperError' has incompatible definitions in different translation units
+// CHECK: struct1.c:56:35: note: field 'f' has type 'int' here
+// CHECK: struct2.c:53:37: note: field 'f' has type 'float' here
+// CHECK: struct1.c:54:8: warning: type 'struct DeepError' has incompatible definitions in different translation units
+// CHECK: struct1.c:56:41: note: field 'Deeper' has type 'struct DeeperError *' here
+// CHECK: struct2.c:53:43: note: field 'Deeper' has type 'struct DeeperError *' here
+// CHECK: struct2.c:54:3: error: external variable 'xDeep' declared with incompatible types in different translation units ('struct DeepError' vs. 'struct DeepError')
+// CHECK: struct1.c:57:3: note: declared here with type 'struct DeepError'
+// CHECK: struct1.c:74:9: warning: type 'S13' has incompatible definitions in different translation units
+// CHECK: struct1.c:75:9: note: field 'i' has type 'Float' (aka 'float') here
+// CHECK: struct2.c:72:7: note: field 'i' has type 'int' here
+// CHECK: struct2.c:76:5: error: external variable 'x13' declared with incompatible types in different translation units ('S13' vs. 'S13')
+// CHECK: struct1.c:79:5: note: declared here with type 'S13'
+// CHECK: struct1.c:130:7: warning: type 'struct DeepUnnamedError::(anonymous at [[PATH_TO_INPUTS:.+]]struct1.c:130:7)' has incompatible definitions in different translation units
+// CHECK: struct1.c:131:14: note: field 'i' has type 'long' here
+// CHECK: struct2.c:128:15: note: field 'i' has type 'float' here
+// CHECK: struct1.c:129:5: warning: type 'union DeepUnnamedError::(anonymous at [[PATH_TO_INPUTS]]struct1.c:129:5)' has incompatible definitions in different translation units
+// CHECK: struct1.c:132:9: note: field 'S' has type 'struct (anonymous struct at [[PATH_TO_INPUTS]]struct1.c:130:7)' here
+// CHECK: struct2.c:129:9: note: field 'S' has type 'struct (anonymous struct at [[PATH_TO_INPUTS]]struct2.c:127:7)' here
+// CHECK: struct2.c:138:3: error: external variable 'x16' declared with incompatible types in different translation units ('struct DeepUnnamedError' vs. 'struct DeepUnnamedError')
+// CHECK: struct1.c:141:3: note: declared here with type 'struct DeepUnnamedError'
+// CHECK: 11 warnings and 9 errors generated
diff --git a/test/ASTMerge/typedef/Inputs/typedef1.c b/test/ASTMerge/typedef/Inputs/typedef1.c
new file mode 100644
index 0000000000..5657675685
--- /dev/null
+++ b/test/ASTMerge/typedef/Inputs/typedef1.c
@@ -0,0 +1,4 @@
+typedef int Typedef1;
+typedef int Typedef2;
+Typedef1 x1;
+Typedef2 x2;
diff --git a/test/ASTMerge/typedef/Inputs/typedef2.c b/test/ASTMerge/typedef/Inputs/typedef2.c
new file mode 100644
index 0000000000..129d7101e9
--- /dev/null
+++ b/test/ASTMerge/typedef/Inputs/typedef2.c
@@ -0,0 +1,4 @@
+typedef int Typedef1;
+typedef double Typedef2;
+Typedef1 x1;
+Typedef2 x2;
diff --git a/test/ASTMerge/typedef/test.c b/test/ASTMerge/typedef/test.c
new file mode 100644
index 0000000000..ec8355d669
--- /dev/null
+++ b/test/ASTMerge/typedef/test.c
@@ -0,0 +1,9 @@
+// FIXME: Errors are now warnings.
+// XFAIL: *
+// RUN: %clang_cc1 -emit-pch -o %t.1.ast %S/Inputs/typedef1.c
+// RUN: %clang_cc1 -emit-pch -o %t.2.ast %S/Inputs/typedef2.c
+// RUN: not %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1 | FileCheck %s
+
+// CHECK: typedef2.c:4:10: error: external variable 'x2' declared with incompatible types in different translation units ('Typedef2' (aka 'double') vs. 'Typedef2' (aka 'int'))
+// CHECK: typedef1.c:4:10: note: declared here with type 'Typedef2' (aka 'int')
+// CHECK: 1 error
diff --git a/test/ASTMerge/unnamed_fields/Inputs/il.cpp b/test/ASTMerge/unnamed_fields/Inputs/il.cpp
new file mode 100644
index 0000000000..1bb0f358dc
--- /dev/null
+++ b/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/test/ASTMerge/unnamed_fields/test.cpp b/test/ASTMerge/unnamed_fields/test.cpp
new file mode 100644
index 0000000000..6ae3176df4
--- /dev/null
+++ b/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/test/ASTMerge/var-cpp/Inputs/var1.cpp b/test/ASTMerge/var-cpp/Inputs/var1.cpp
new file mode 100644
index 0000000000..e29db9d43f
--- /dev/null
+++ b/test/ASTMerge/var-cpp/Inputs/var1.cpp
@@ -0,0 +1,17 @@
+
+template <typename T>
+constexpr T my_pi = T(3.1415926535897932385L); // variable template
+
+template <> constexpr char my_pi<char> = '3'; // variable template specialization
+
+template <typename T>
+struct Wrapper {
+ template <typename U> static constexpr U my_const = U(1);
+ // Variable template partial specialization with member variable.
+ template <typename U> static constexpr U *my_const<const U *> = (U *)(0);
+};
+
+constexpr char a[] = "hello";
+
+template <> template <>
+constexpr const char *Wrapper<float>::my_const<const char *> = a;
diff --git a/test/ASTMerge/var-cpp/test.cpp b/test/ASTMerge/var-cpp/test.cpp
new file mode 100644
index 0000000000..28d38d5812
--- /dev/null
+++ b/test/ASTMerge/var-cpp/test.cpp
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -emit-pch -std=c++17 -o %t.1.ast %S/Inputs/var1.cpp
+// RUN: %clang_cc1 -std=c++17 -ast-merge %t.1.ast -fsyntax-only %s 2>&1
+
+static_assert(my_pi<double> == (double)3.1415926535897932385L);
+static_assert(my_pi<char> == '3');
+
+static_assert(Wrapper<int>::my_const<float> == 1.f);
+static_assert(Wrapper<char>::my_const<const float *> == nullptr);
+static_assert(Wrapper<float>::my_const<const char *> == a);
diff --git a/test/ASTMerge/var/Inputs/var1.c b/test/ASTMerge/var/Inputs/var1.c
new file mode 100644
index 0000000000..4f5cbe16ab
--- /dev/null
+++ b/test/ASTMerge/var/Inputs/var1.c
@@ -0,0 +1,7 @@
+int *x0;
+float **x1;
+#include "var1.h"
+int xarray0[17];
+int xarray1[];
+int xarray2[18];
+int xarray3[18];
diff --git a/test/ASTMerge/var/Inputs/var1.h b/test/ASTMerge/var/Inputs/var1.h
new file mode 100644
index 0000000000..1518e17ef0
--- /dev/null
+++ b/test/ASTMerge/var/Inputs/var1.h
@@ -0,0 +1 @@
+double x2;
diff --git a/test/ASTMerge/var/Inputs/var2.c b/test/ASTMerge/var/Inputs/var2.c
new file mode 100644
index 0000000000..01986e4208
--- /dev/null
+++ b/test/ASTMerge/var/Inputs/var2.c
@@ -0,0 +1,7 @@
+int *x0;
+double *x1;
+int x2;
+int xarray0[17];
+int xarray1[17];
+int xarray2[];
+int xarray3[17];
diff --git a/test/ASTMerge/var/test.c b/test/ASTMerge/var/test.c
new file mode 100644
index 0000000000..f0a3d92b7d
--- /dev/null
+++ b/test/ASTMerge/var/test.c
@@ -0,0 +1,14 @@
+// FIXME: Errors are now warnings.
+// XFAIL: *
+// RUN: %clang_cc1 -emit-pch -o %t.1.ast %S/Inputs/var1.c
+// RUN: %clang_cc1 -emit-pch -o %t.2.ast %S/Inputs/var2.c
+// RUN: not %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only -fdiagnostics-show-note-include-stack %s 2>&1 | FileCheck %s
+
+// CHECK: var2.c:2:9: error: external variable 'x1' declared with incompatible types in different translation units ('double *' vs. 'float **')
+// CHECK: var1.c:2:9: note: declared here with type 'float **'
+// CHECK: var2.c:3:5: error: external variable 'x2' declared with incompatible types in different translation units ('int' vs. 'double')
+// CHECK: In file included from{{.*}}var1.c:3:
+// CHECK: var1.h:1:8: note: declared here with type 'double'
+// CHECK: error: external variable 'xarray3' declared with incompatible types in different translation units ('int [17]' vs. 'int [18]')
+// CHECK: var1.c:7:5: note: declared here with type 'int [18]'
+// CHECK: 3 errors