Updated with Alexey's comments.

http://reviews.llvm.org/D7525

Files:
  include/clang/Driver/ToolChain.h
  lib/Driver/SanitizerArgs.cpp
  lib/Driver/ToolChain.cpp
  lib/Driver/Tools.cpp
  test/Driver/fsanitize.c
  test/Driver/rtti-options.cpp

EMAIL PREFERENCES
  http://reviews.llvm.org/settings/panel/emailpreferences/
Index: include/clang/Driver/ToolChain.h
===================================================================
--- include/clang/Driver/ToolChain.h
+++ include/clang/Driver/ToolChain.h
@@ -53,6 +53,13 @@
     RLT_Libgcc
   };
 
+  enum RTTIMode {
+    RM_EnabledExplicitly,
+    RM_EnabledImplicitly,
+    RM_DisabledExplicitly,
+    RM_DisabledImplicitly
+  };
+
 private:
   const Driver &D;
   const llvm::Triple Triple;
@@ -74,6 +81,7 @@
   Tool *getLink() const;
   Tool *getClangAs() const;
 
+  const RTTIMode CachedRTTIMode;
   mutable std::unique_ptr<SanitizerArgs> SanitizerArguments;
 
 protected:
@@ -134,6 +142,9 @@
 
   const SanitizerArgs& getSanitizerArgs() const;
 
+  // Returns the RTTIMode for the toolchain with the current arguments.
+  RTTIMode getRTTIMode() const { return CachedRTTIMode; }
+
   // Tool access.
 
   /// TranslateArgs - Create a new derived argument list for any argument
Index: lib/Driver/SanitizerArgs.cpp
===================================================================
--- lib/Driver/SanitizerArgs.cpp
+++ lib/Driver/SanitizerArgs.cpp
@@ -171,6 +171,8 @@
                                 // Used to deduplicate diagnostics.
   unsigned Kinds = 0;
   unsigned NotSupported = getToolchainUnsupportedKinds(TC);
+  ToolChain::RTTIMode RTTIMode = TC.getRTTIMode();
+
   const Driver &D = TC.getDriver();
   for (ArgList::const_reverse_iterator I = Args.rbegin(), E = Args.rend();
        I != E; ++I) {
@@ -193,6 +195,30 @@
       }
       Add &= ~NotSupported;
 
+      // Test for -fno-rtti + explicit -fsanitizer=vptr before expanding groups
+      // so we don't error out if -fno-rtti and -fsanitize=undefined were
+      // passed.
+      if (Add & static_cast<unsigned>(SanitizeKind::Vptr) &&
+          (RTTIMode == ToolChain::RM_DisabledImplicitly ||
+           RTTIMode == ToolChain::RM_DisabledExplicitly)) {
+        if (RTTIMode == ToolChain::RM_DisabledImplicitly)
+          // Warn about not having rtti enabled if the vptr sanitizer is
+          // explicitly enabled
+          D.Diag(diag::warn_drv_disabling_vptr_no_rtti_default);
+        else {
+          llvm::opt::Arg *NoRTTIArg =
+              Args.getLastArg(options::OPT_mkernel, options::OPT_fapple_kext,
+                              options::OPT_fno_rtti);
+          assert(NoRTTIArg &&
+                 "RTTI disabled explicitly but we have no argument!");
+          D.Diag(diag::err_drv_argument_not_allowed_with)
+              << "-fsanitize=vptr" << NoRTTIArg->getAsString(Args);
+        }
+
+        // Take out the Vptr sanitizer from the enabled sanitizers
+        AllRemove |= static_cast<unsigned>(SanitizeKind::Vptr);
+      }
+
       Add = expandGroups(Add);
       // Group expansion may have enabled a sanitizer which is disabled later.
       Add &= ~AllRemove;
@@ -209,6 +235,14 @@
   }
   addAllOf(Sanitizers, Kinds);
 
+  // Warn that we're disabling the vptr sanitizer if -fno-rtti and
+  // -fsanitize=undefined were passed.
+  if (Sanitizers.has(SanitizerKind::Vptr) &&
+      (RTTIMode == ToolChain::RM_DisabledImplicitly ||
+       RTTIMode == ToolChain::RM_DisabledExplicitly)) {
+    Sanitizers.set(SanitizerKind::Vptr, 0);
+  }
+
   // Parse -f(no-)?sanitize-recover flags.
   unsigned RecoverableKinds = RecoverableByDefault;
   unsigned DiagnosedUnrecoverableKinds = 0;
Index: lib/Driver/ToolChain.cpp
===================================================================
--- lib/Driver/ToolChain.cpp
+++ lib/Driver/ToolChain.cpp
@@ -26,14 +26,44 @@
 using namespace clang;
 using namespace llvm::opt;
 
+static ToolChain::RTTIMode calculateRTTIMode(const ArgList &Args,
+                                             const llvm::Triple &Triple) {
+  // Explicit rtti/no-rtti args
+  Arg *RTTIArg = Args.getLastArg(options::OPT_mkernel, options::OPT_fapple_kext,
+                                 options::OPT_fno_rtti, options::OPT_frtti);
+  if (RTTIArg) {
+    if (RTTIArg->getOption().matches(options::OPT_frtti))
+      return ToolChain::RM_EnabledExplicitly;
+    else
+      return ToolChain::RM_DisabledExplicitly;
+  }
+
+  // -frtti is default, except for the PS4 CPU.
+  if (!Triple.isPS4CPU())
+    return ToolChain::RM_EnabledImplicitly;
+
+  // On the PS4, turning on c++ exceptions turns on rtti.
+  // We're assuming that, if we see -fexceptions, rtti gets turned on.
+  Arg *Exceptions = Args.getLastArg(
+      options::OPT_fcxx_exceptions, options::OPT_fno_cxx_exceptions,
+      options::OPT_fexceptions, options::OPT_fno_exceptions);
+  if (Exceptions &&
+      (Exceptions->getOption().matches(options::OPT_fexceptions) ||
+       Exceptions->getOption().matches(options::OPT_fcxx_exceptions))) {
+    return ToolChain::RM_EnabledImplicitly;
+  } else {
+    return ToolChain::RM_DisabledImplicitly;
+  }
+}
+
 ToolChain::ToolChain(const Driver &D, const llvm::Triple &T,
                      const ArgList &Args)
-  : D(D), Triple(T), Args(Args) {
+    : D(D), Triple(T), Args(Args),
+      CachedRTTIMode(calculateRTTIMode(Args, Triple)) {
   if (Arg *A = Args.getLastArg(options::OPT_mthread_model))
     if (!isThreadModelSupported(A->getValue()))
       D.Diag(diag::err_drv_invalid_thread_model_for_target)
-          << A->getValue()
-          << A->getAsString(Args);
+          << A->getValue() << A->getAsString(Args);
 }
 
 ToolChain::~ToolChain() {
Index: lib/Driver/Tools.cpp
===================================================================
--- lib/Driver/Tools.cpp
+++ lib/Driver/Tools.cpp
@@ -1932,16 +1932,17 @@
   return false;
 }
 
-/// addExceptionArgs - Adds exception related arguments to the driver command
-/// arguments. There's a master flag, -fexceptions and also language specific
-/// flags to enable/disable C++ and Objective-C exceptions.
-/// This makes it possible to for example disable C++ exceptions but enable
-/// Objective-C exceptions.
+/// Adds exception related arguments to the driver command arguments.
+/// There's a master flag, -fexceptions and also language specific flags to
+/// enable/disable C++ and Objective-C exceptions./ This makes it possible to
+/// for example disable C++ exceptions but enable Objective-C exceptions.
 static void addExceptionArgs(const ArgList &Args, types::ID InputType,
-                             const llvm::Triple &Triple,
-                             bool KernelOrKext,
+                             const ToolChain &TC, bool KernelOrKext,
                              const ObjCRuntime &objcRuntime,
                              ArgStringList &CmdArgs) {
+  const Driver &D = TC.getDriver();
+  const llvm::Triple &Triple = TC.getTriple();
+
   if (KernelOrKext) {
     // -mkernel and -fapple-kext imply no exceptions, so claim exception related
     // arguments now to avoid warnings about unused arguments.
@@ -1971,15 +1972,26 @@
   if (types::isCXX(InputType)) {
     bool CXXExceptionsEnabled =
         Triple.getArch() != llvm::Triple::xcore && !Triple.isPS4CPU();
-    if (Arg *A = Args.getLastArg(options::OPT_fcxx_exceptions,
-                                 options::OPT_fno_cxx_exceptions,
-                                 options::OPT_fexceptions,
-                                 options::OPT_fno_exceptions))
+    Arg *A = Args.getLastArg(
+        options::OPT_fcxx_exceptions, options::OPT_fno_cxx_exceptions,
+        options::OPT_fexceptions, options::OPT_fno_exceptions);
+    if (A)
       CXXExceptionsEnabled =
           A->getOption().matches(options::OPT_fcxx_exceptions) ||
           A->getOption().matches(options::OPT_fexceptions);
 
     if (CXXExceptionsEnabled) {
+      ToolChain::RTTIMode RTTIMode = TC.getRTTIMode();
+      if (Triple.isPS4CPU()) {
+        assert(A && "On the PS4 exceptions should only be enabled if passing "
+                    "an argument");
+        if (RTTIMode == ToolChain::RM_DisabledExplicitly)
+          D.Diag(diag::err_drv_argument_not_allowed_with)
+              << "-fno-rtti" << A->getAsString(Args);
+        else if (RTTIMode == ToolChain::RM_EnabledImplicitly)
+          D.Diag(diag::warn_drv_enabling_rtti_with_exceptions);
+      }
+
       CmdArgs.push_back("-fcxx-exceptions");
 
       EH = true;
@@ -4006,56 +4018,11 @@
                    false))
     CmdArgs.push_back("-fno-elide-constructors");
 
-  // -frtti is default, except for the PS4 CPU.
-  if (!Args.hasFlag(options::OPT_frtti, options::OPT_fno_rtti,
-                    !Triple.isPS4CPU()) ||
-      KernelOrKext) {
-    bool IsCXX = types::isCXX(InputType);
-    bool RTTIEnabled = false;
-    Arg *NoRTTIArg = Args.getLastArg(
-        options::OPT_mkernel, options::OPT_fapple_kext, options::OPT_fno_rtti);
-
-    // PS4 requires rtti when exceptions are enabled. If -fno-rtti was
-    // explicitly passed, error out. Otherwise enable rtti and emit a
-    // warning.
-    Arg *Exceptions = Args.getLastArg(
-        options::OPT_fcxx_exceptions, options::OPT_fno_cxx_exceptions,
-        options::OPT_fexceptions, options::OPT_fno_exceptions);
-    if (Triple.isPS4CPU() && Exceptions) {
-      bool CXXExceptions =
-          (IsCXX &&
-           Exceptions->getOption().matches(options::OPT_fexceptions)) ||
-          Exceptions->getOption().matches(options::OPT_fcxx_exceptions);
-      if (CXXExceptions) {
-        if (NoRTTIArg)
-          D.Diag(diag::err_drv_argument_not_allowed_with)
-              << NoRTTIArg->getAsString(Args) << Exceptions->getAsString(Args);
-        else {
-          RTTIEnabled = true;
-          D.Diag(diag::warn_drv_enabling_rtti_with_exceptions);
-        }
-      }
-    }
+  ToolChain::RTTIMode RTTIMode = getToolChain().getRTTIMode();
 
-    // -fno-rtti cannot usefully be combined with -fsanitize=vptr.
-    if (Sanitize.sanitizesVptr()) {
-      // If rtti was explicitly disabled and the vptr sanitizer is on, error
-      // out. Otherwise, warn that vptr will be disabled unless -frtti is
-      // passed.
-      if (NoRTTIArg) {
-        D.Diag(diag::err_drv_argument_not_allowed_with)
-            << "-fsanitize=vptr" << NoRTTIArg->getAsString(Args);
-      } else {
-        D.Diag(diag::warn_drv_disabling_vptr_no_rtti_default);
-        // All sanitizer switches have been pushed. This -fno-sanitize
-        // will override any -fsanitize={vptr,undefined} passed before it.
-        CmdArgs.push_back("-fno-sanitize=vptr");
-      }
-    }
-
-    if (!RTTIEnabled)
-      CmdArgs.push_back("-fno-rtti");
-  }
+  if (RTTIMode == ToolChain::RM_DisabledExplicitly ||
+      RTTIMode == ToolChain::RM_DisabledImplicitly)
+    CmdArgs.push_back("-fno-rtti");
 
   // -fshort-enums=0 is default for all architectures except Hexagon.
   if (Args.hasFlag(options::OPT_fshort_enums,
@@ -4233,7 +4200,7 @@
 
   // Handle GCC-style exception args.
   if (!C.getDriver().IsCLMode())
-    addExceptionArgs(Args, InputType, getToolChain().getTriple(), KernelOrKext,
+    addExceptionArgs(Args, InputType, getToolChain(), KernelOrKext,
                      objcRuntime, CmdArgs);
 
   if (getToolChain().UseSjLjExceptions())
Index: test/Driver/fsanitize.c
===================================================================
--- test/Driver/fsanitize.c
+++ test/Driver/fsanitize.c
@@ -31,7 +31,6 @@
 // CHECK-UNDEFINED-TRAP-ON-ERROR-VPTR: '-fsanitize=vptr' not allowed with '-fsanitize-undefined-trap-on-error'
 
 // RUN: %clang -target x86_64-linux-gnu -fsanitize=vptr -fno-rtti %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-VPTR-NO-RTTI
-// RUN: %clang -target x86_64-linux-gnu -fsanitize=undefined -fno-rtti %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-VPTR-NO-RTTI
 // CHECK-VPTR-NO-RTTI: '-fsanitize=vptr' not allowed with '-fno-rtti'
 
 // RUN: %clang -target x86_64-linux-gnu -fsanitize=address,thread -fno-rtti %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANA-SANT
Index: test/Driver/rtti-options.cpp
===================================================================
--- test/Driver/rtti-options.cpp
+++ test/Driver/rtti-options.cpp
@@ -3,19 +3,23 @@
 // No warnings/errors should be emitted for unknown, except if combining
 // the vptr sanitizer with -fno-rtti
 
+// RUN: %clang -### -c -fno-rtti -frtti %s 2>&1 | FileCheck -check-prefix=CHECK-RTTI %s
+// RUN: %clang -### -c -frtti -fno-rtti %s 2>&1 | FileCheck -check-prefix=CHECK-NO-RTTI %s
+
 // -fsanitize=vptr
+// Make sure we only error/warn once, when trying to enable vptr and
+// undefined and have -fno-rtti
+// RUN: %clang -### -c -fsanitize=undefined -fsanitize=vptr -fno-rtti %s 2>&1 | FileCheck -check-prefix=CHECK-SAN-ERROR -check-prefix=CHECK-OK %s
+
 // RUN: %clang -### -c -target x86_64-scei-ps4 -fsanitize=vptr %s 2>&1 | FileCheck -check-prefix=CHECK-SAN-WARN %s
 // RUN: %clang -### -c -target x86_64-scei-ps4 -fsanitize=vptr -frtti %s 2>&1 | FileCheck -check-prefix=CHECK-OK %s
 // RUN: %clang -### -c -target x86_64-scei-ps4 -fsanitize=vptr -fno-rtti %s 2>&1 | FileCheck -check-prefix=CHECK-SAN-ERROR %s
-// RUN: %clang -### -c -target x86_64-scei-ps4 -fsanitize=undefined %s 2>&1 | FileCheck -check-prefix=CHECK-SAN-WARN %s
 // RUN: %clang -### -c -target x86_64-scei-ps4 -fsanitize=undefined -frtti %s 2>&1 | FileCheck -check-prefix=CHECK-OK %s
-// RUN: %clang -### -c -target x86_64-scei-ps4 -fsanitize=undefined -fno-rtti %s 2>&1 | FileCheck -check-prefix=CHECK-SAN-ERROR %s
 // RUN: %clang -### -c -target x86_64-unknown-unknown -fsanitize=vptr %s 2>&1 | FileCheck -check-prefix=CHECK-OK %s
 // RUN: %clang -### -c -target x86_64-unknown-unknown -fsanitize=vptr -frtti %s 2>&1 | FileCheck -check-prefix=CHECK-OK %s
 // RUN: %clang -### -c -target x86_64-unknown-unknown -fsanitize=vptr -fno-rtti %s 2>&1 | FileCheck -check-prefix=CHECK-SAN-ERROR %s
 // RUN: %clang -### -c -target x86_64-unknown-unknown -fsanitize=undefined %s 2>&1 | FileCheck -check-prefix=CHECK-OK %s
 // RUN: %clang -### -c -target x86_64-unknown-unknown -fsanitize=undefined -frtti %s 2>&1 | FileCheck -check-prefix=CHECK-OK %s
-// RUN: %clang -### -c -target x86_64-unknown-unknown -fsanitize=undefined -fno-rtti %s 2>&1 | FileCheck -check-prefix=CHECK-SAN-ERROR %s
 
 // Exceptions + no/default rtti
 // RUN: %clang -### -c -target x86_64-scei-ps4 -fcxx-exceptions -fno-rtti %s 2>&1 | FileCheck -check-prefix=CHECK-EXC-ERROR-CXX %s
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to