From fb809189d3310328602d795b0ce9c77dc3452351 Mon Sep 17 00:00:00 2001
From: Ben Morgan <drbenmorgan@users.noreply.github.com>
Date: Tue, 13 Dec 2016 21:15:10 +0000
Subject: Better cxx11/14/17 flags for GNU/Clang/Intel (#2539)

* Better cxx11/14 flags for GNU/Clang/Intel

- GCC 4.8 only supports -std=c++1y for C++14
- Use CMake's rules for AppleClang to set cxx11 and cxx14 flags based on
  Apple Xcode/LLVM version
- Use CMake's rules for Intel to add support for cxx14 flags based on
  Intel version.

* Add cxx17_flag property

Implement property in compiler for c++17 as per those for c++11/14.
Add concrete support for GNU/Clang:

- Return -std=c++1z for GCC 5 and above per GCC documentation
- Return -std=c++1z for Clang 3.5 and above per Clang documentation
- Return -std=c++1z for Apple LLVM 6.1 and above per CMake's rules
---
 lib/spack/spack/compiler.py        | 10 ++++++++++
 lib/spack/spack/compilers/clang.py | 40 ++++++++++++++++++++++++++++++++++++--
 lib/spack/spack/compilers/gcc.py   |  9 +++++++++
 lib/spack/spack/compilers/intel.py | 10 ++++++++++
 4 files changed, 67 insertions(+), 2 deletions(-)

diff --git a/lib/spack/spack/compiler.py b/lib/spack/spack/compiler.py
index 92fa1ac4db..d5ea85a7b7 100644
--- a/lib/spack/spack/compiler.py
+++ b/lib/spack/spack/compiler.py
@@ -183,6 +183,16 @@ class Compiler(object):
             "If you think it should, please edit the compiler subclass and",
             "submit a pull request or issue.")
 
+    # This property should be overridden in the compiler subclass if
+    # C++17 is supported by that compiler
+    @property
+    def cxx17_flag(self):
+        # If it is not overridden, assume it is not supported and warn the user
+        tty.die(
+            "The compiler you have chosen does not currently support C++17.",
+            "If you think it should, please edit the compiler subclass and",
+            "submit a pull request or issue.")
+
     #
     # Compiler classes have methods for querying the version of
     # specific compiler executables.  This is used when discovering compilers.
diff --git a/lib/spack/spack/compilers/clang.py b/lib/spack/spack/compilers/clang.py
index 14dc9d6476..3d68a37c44 100644
--- a/lib/spack/spack/compilers/clang.py
+++ b/lib/spack/spack/compilers/clang.py
@@ -70,14 +70,50 @@ class Clang(Compiler):
     @property
     def cxx11_flag(self):
         if self.is_apple:
-            # FIXME: figure out from which version Apple's clang supports c++11
-            return "-std=c++11"
+            # Adapted from CMake's AppleClang-CXX rules
+            # Spack's AppleClang detection only valid form Xcode >= 4.6
+            if self.version < ver('4.0.0'):
+                tty.die("Only Apple LLVM 4.0 and above support c++11")
+            else:
+                return "-std=c++11"
         else:
             if self.version < ver('3.3'):
                 tty.die("Only Clang 3.3 and above support c++11.")
             else:
                 return "-std=c++11"
 
+    @property
+    def cxx14_flag(self):
+        if self.is_apple:
+            # Adapted from CMake's rules for AppleClang
+            if self.version < ver('5.1.0'):
+                tty.die("Only Apple LLVM 5.1 and above support c++14.")
+            elif self.version < ver('6.1.0'):
+                return "-std=c++1y"
+            else:
+                return "-std=c++14"
+        else:
+            if self.version < ver('3.4'):
+                tty.die("Only Clang 3.4 and above support c++14.")
+            elif self.version < ver('3.5'):
+                return "-std=c++1y"
+            else:
+                return "-std=c++14"
+
+    @property
+    def cxx17_flag(self):
+        if self.is_apple:
+            # Adapted from CMake's rules for AppleClang
+            if self.version < ver('6.1.0'):
+                tty.die("Only Apple LLVM 6.1 and above support c++17.")
+            else:
+                return "-std=c++1z"
+        else:
+            if self.version < ver('3.5'):
+                tty.die("Only Clang 3.5 and above support c++17.")
+            else:
+                return "-std=c++1z"
+
     @property
     def pic_flag(self):
         return "-fPIC"
diff --git a/lib/spack/spack/compilers/gcc.py b/lib/spack/spack/compilers/gcc.py
index 80d24910c3..304f82a492 100644
--- a/lib/spack/spack/compilers/gcc.py
+++ b/lib/spack/spack/compilers/gcc.py
@@ -71,9 +71,18 @@ class Gcc(Compiler):
     def cxx14_flag(self):
         if self.version < ver('4.8'):
             tty.die("Only gcc 4.8 and above support c++14.")
+        elif self.version < ver('4.9'):
+            return "-std=c++1y"
         else:
             return "-std=c++14"
 
+    @property
+    def cxx17_flag(self):
+        if self.version < ver('5.0'):
+            tty.die("Only gcc 5.0 and above support c++17.")
+        else:
+            return "-std=c++1z"
+
     @property
     def pic_flag(self):
         return "-fPIC"
diff --git a/lib/spack/spack/compilers/intel.py b/lib/spack/spack/compilers/intel.py
index 4ff7185c84..8461753962 100644
--- a/lib/spack/spack/compilers/intel.py
+++ b/lib/spack/spack/compilers/intel.py
@@ -65,6 +65,16 @@ class Intel(Compiler):
         else:
             return "-std=c++11"
 
+    @property
+    def cxx14_flag(self):
+        # Adapted from CMake's Intel-CXX rules.
+        if self.version < ver('15'):
+            tty.die("Only intel 15.0 and above support c++14.")
+        elif self.version < ver('15.0.2'):
+            return "-std=c++1y"
+        else:
+            return "-std=c++14"
+
     @property
     def pic_flag(self):
         return "-fPIC"
-- 
cgit v1.2.3-70-g09d2