erik.pilkington created this revision.

This patch adds lit testing support for Objective-C++. I'm going to be working 
on improving Objective-C++ support in libc++ this summer, and it would be nice 
to write tests. I tested this patch on Ubuntu 16.04 with gcc 5.4, and it works 
fine (the .mm tests become UNSUPPORTED).

Thanks for taking a look!
Erik


https://reviews.llvm.org/D33049

Files:
  test/libcxx/selftest/test.fail.mm
  test/libcxx/selftest/test.pass.mm
  utils/libcxx/compiler.py
  utils/libcxx/test/config.py
  utils/libcxx/test/format.py

Index: utils/libcxx/test/format.py
===================================================================
--- utils/libcxx/test/format.py
+++ utils/libcxx/test/format.py
@@ -87,9 +87,10 @@
         name_root, name_ext = os.path.splitext(name)
         is_libcxx_test = test.path_in_suite[0] == 'libcxx'
         is_sh_test = name_root.endswith('.sh')
-        is_pass_test = name.endswith('.pass.cpp')
-        is_fail_test = name.endswith('.fail.cpp')
-        assert is_sh_test or name_ext == '.cpp', 'non-cpp file must be sh test'
+        is_pass_test = name.endswith('.pass.cpp') or name.endswith('.pass.mm')
+        is_fail_test = name.endswith('.fail.cpp') or name.endswith('.fail.mm')
+        assert is_sh_test or name_ext == '.cpp' or name_ext == '.mm', \
+            'non-cpp file must be sh test'
 
         if test.config.unsupported:
             return (lit.Test.UNSUPPORTED,
@@ -133,6 +134,8 @@
                 if '#define _LIBCPP_ASSERT' in contents:
                     test_cxx.useModules(False)
 
+        is_objcxx = name_ext == '.mm'
+
         # Dispatch the test based on its suffix.
         if is_sh_test:
             if not isinstance(self.executor, LocalExecutor):
@@ -144,19 +147,19 @@
                                              self.execute_external, script,
                                              tmpBase)
         elif is_fail_test:
-            return self._evaluate_fail_test(test, test_cxx, parsers)
+            return self._evaluate_fail_test(test, test_cxx, parsers, is_objcxx)
         elif is_pass_test:
             return self._evaluate_pass_test(test, tmpBase, lit_config,
-                                            test_cxx, parsers)
+                                            test_cxx, parsers, is_objcxx)
         else:
             # No other test type is supported
             assert False
 
     def _clean(self, exec_path):  # pylint: disable=no-self-use
         libcxx.util.cleanFile(exec_path)
 
     def _evaluate_pass_test(self, test, tmpBase, lit_config,
-                            test_cxx, parsers):
+                            test_cxx, parsers, is_objcxx):
         execDir = os.path.dirname(test.getExecPath())
         source_path = test.getSourcePath()
         exec_path = tmpBase + '.exe'
@@ -166,8 +169,8 @@
         try:
             # Compile the test
             cmd, out, err, rc = test_cxx.compileLinkTwoSteps(
-                source_path, out=exec_path, object_file=object_path,
-                cwd=execDir)
+                source_path, is_objcxx=is_objcxx, out=exec_path,
+                object_file=object_path, cwd=execDir)
             compile_cmd = cmd
             if rc != 0:
                 report = libcxx.util.makeReport(cmd, out, err, rc)
@@ -206,7 +209,7 @@
             libcxx.util.cleanFile(object_path)
             self._clean(exec_path)
 
-    def _evaluate_fail_test(self, test, test_cxx, parsers):
+    def _evaluate_fail_test(self, test, test_cxx, parsers, is_objcxx):
         source_path = test.getSourcePath()
         # FIXME: lift this detection into LLVM/LIT.
         with open(source_path, 'r') as f:
@@ -227,7 +230,8 @@
             if '-Wuser-defined-warnings' in test_cxx.warning_flags:
                 test_cxx.warning_flags += ['-Wno-error=user-defined-warnings']
 
-        cmd, out, err, rc = test_cxx.compile(source_path, out=os.devnull)
+        cmd, out, err, rc = test_cxx.compile(source_path, out=os.devnull,
+                                             is_objcxx=is_objcxx)
         expected_rc = 0 if use_verify else 1
         if rc == expected_rc:
             return lit.Test.PASS, ''
Index: utils/libcxx/test/config.py
===================================================================
--- utils/libcxx/test/config.py
+++ utils/libcxx/test/config.py
@@ -462,6 +462,12 @@
             self.config.available_features.add('glibc-%s' % maj_v)
             self.config.available_features.add('glibc-%s.%s' % (maj_v, min_v))
 
+        # Support Objective-C++ only on MacOS and if the compiler supports it.
+        if not self.target_info.platform() == "darwin" or \
+           not self.target_info.is_host_macosx() or \
+           not self.cxx.hasCompileFlag(["-x", "objective-c++", "-fobjc-arc"]):
+            self.config.available_features.add("no-objective-cxx")
+
     def configure_compile_flags(self):
         no_default_flags = self.get_lit_bool('no_default_flags', False)
         if not no_default_flags:
Index: utils/libcxx/compiler.py
===================================================================
--- utils/libcxx/compiler.py
+++ utils/libcxx/compiler.py
@@ -98,17 +98,20 @@
         self.version = (major_ver, minor_ver, patchlevel)
 
     def _basicCmd(self, source_files, out, mode=CM_Default, flags=[],
-                  input_is_cxx=False):
+                  input_is_text=False, is_objcxx=False):
         cmd = []
         if self.use_ccache \
                 and not mode == self.CM_Link \
                 and not mode == self.CM_PreProcess:
             cmd += ['ccache']
         cmd += [self.path]
         if out is not None:
             cmd += ['-o', out]
-        if input_is_cxx:
-            cmd += ['-x', 'c++']
+        if input_is_text:
+            if is_objcxx:
+                cmd += ['-x', 'objective-c++', '-fobjc-arc']
+            else:
+                cmd += ['-x', 'c++']
         if isinstance(source_files, list):
             cmd += source_files
         elif isinstance(source_files, str):
@@ -131,22 +134,25 @@
                 cmd += self.warning_flags
         if mode != self.CM_PreProcess and mode != self.CM_Compile:
             cmd += self.link_flags
+            if is_objcxx:
+                cmd += ['-framework', 'Foundation']
         cmd += flags
         return cmd
 
     def preprocessCmd(self, source_files, out=None, flags=[]):
         return self._basicCmd(source_files, out, flags=flags,
-                             mode=self.CM_PreProcess,
-                             input_is_cxx=True)
+                              mode=self.CM_PreProcess,
+                              input_is_text=True)
 
-    def compileCmd(self, source_files, out=None, flags=[]):
+    def compileCmd(self, source_files, out=None, flags=[], is_objcxx=False):
         return self._basicCmd(source_files, out, flags=flags,
-                             mode=self.CM_Compile,
-                             input_is_cxx=True) + ['-c']
+                              mode=self.CM_Compile,
+                              input_is_text=True,
+                              is_objcxx=is_objcxx) + ['-c']
 
-    def linkCmd(self, source_files, out=None, flags=[]):
+    def linkCmd(self, source_files, out=None, flags=[], is_objcxx=False):
         return self._basicCmd(source_files, out, flags=flags,
-                              mode=self.CM_Link)
+                              mode=self.CM_Link, is_objcxx=is_objcxx)
 
     def compileLinkCmd(self, source_files, out=None, flags=[]):
         return self._basicCmd(source_files, out, flags=flags)
@@ -157,14 +163,15 @@
                                                   cwd=cwd)
         return cmd, out, err, rc
 
-    def compile(self, source_files, out=None, flags=[], cwd=None):
-        cmd = self.compileCmd(source_files, out, flags)
+    def compile(self, source_files, out=None, flags=[], cwd=None,
+                is_objcxx=False):
+        cmd = self.compileCmd(source_files, out, flags, is_objcxx)
         out, err, rc = libcxx.util.executeCommand(cmd, env=self.compile_env,
                                                   cwd=cwd)
         return cmd, out, err, rc
 
-    def link(self, source_files, out=None, flags=[], cwd=None):
-        cmd = self.linkCmd(source_files, out, flags)
+    def link(self, source_files, out=None, flags=[], cwd=None, is_objcxx=False):
+        cmd = self.linkCmd(source_files, out, flags, is_objcxx)
         out, err, rc = libcxx.util.executeCommand(cmd, env=self.compile_env,
                                                   cwd=cwd)
         return cmd, out, err, rc
@@ -176,8 +183,8 @@
                                                   cwd=cwd)
         return cmd, out, err, rc
 
-    def compileLinkTwoSteps(self, source_file, out=None, object_file=None,
-                            flags=[], cwd=None):
+    def compileLinkTwoSteps(self, source_file, is_objcxx, out=None,
+                            object_file=None, flags=[], cwd=None):
         if not isinstance(source_file, str):
             raise TypeError('This function only accepts a single input file')
         if object_file is None:
@@ -188,12 +195,13 @@
             with_fn = lambda: libcxx.util.nullContext(object_file)
         with with_fn() as object_file:
             cc_cmd, cc_stdout, cc_stderr, rc = self.compile(
-                source_file, object_file, flags=flags, cwd=cwd)
+                source_file, object_file, flags=flags, cwd=cwd,
+                is_objcxx=is_objcxx)
             if rc != 0:
                 return cc_cmd, cc_stdout, cc_stderr, rc
 
             link_cmd, link_stdout, link_stderr, rc = self.link(
-                object_file, out=out, flags=flags, cwd=cwd)
+                object_file, out=out, flags=flags, cwd=cwd, is_objcxx=is_objcxx)
             return (cc_cmd + ['&&'] + link_cmd, cc_stdout + link_stdout,
                     cc_stderr + link_stderr, rc)
 
Index: test/libcxx/selftest/test.pass.mm
===================================================================
--- test/libcxx/selftest/test.pass.mm
+++ test/libcxx/selftest/test.pass.mm
@@ -0,0 +1,15 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: no-objective-cxx
+
+int main()
+{
+}
Index: test/libcxx/selftest/test.fail.mm
===================================================================
--- test/libcxx/selftest/test.fail.mm
+++ test/libcxx/selftest/test.fail.mm
@@ -0,0 +1,13 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: no-objective-cxx
+
+#error This test should not compile.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to