]> granicus.if.org Git - clang/commitdiff
[CTU] Add triple/lang mismatch handling
authorGabor Marton <martongabesz@gmail.com>
Fri, 7 Dec 2018 16:32:43 +0000 (16:32 +0000)
committerGabor Marton <martongabesz@gmail.com>
Fri, 7 Dec 2018 16:32:43 +0000 (16:32 +0000)
Summary:
We introduce a strict policy for C++ CTU. It can work across TUs only if
the C++ dialects are the same. We neither allow C vs C++ CTU.  We do this
because the same constructs might be represented with different properties in
the corresponding AST nodes or even the nodes might be completely different (a
struct will be RecordDecl in C, but it will be a CXXRectordDecl in C++, thus it
may cause certain assertions during cast operations).

Reviewers: xazax.hun, a_sidorin

Subscribers: rnkovacs, dkrupp, Szelethus, gamesh411, cfe-commits

Differential Revision: https://reviews.llvm.org/D55134

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@348610 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticCrossTUKinds.td
include/clang/Basic/DiagnosticGroups.td
include/clang/CrossTU/CrossTranslationUnit.h
lib/CrossTU/CrossTranslationUnit.cpp
test/Analysis/ctu-different-triples.cpp [new file with mode: 0644]
test/Analysis/ctu-unknown-parts-in-triples.cpp [new file with mode: 0644]

index 8b6d8b681445d6a2596d6396bafa43b40d7974df..877ac3d575d7f06d4a031138bee20bcb2203abd1 100644 (file)
@@ -15,4 +15,8 @@ def err_fnmap_parsing : Error<
 
 def err_multiple_def_index : Error<
   "multiple definitions are found for the same key in index ">;
+
+def warn_ctu_incompat_triple : Warning<
+  "imported AST from '%0' had been generated for a different target, "
+  "current: %1, imported: %2">, InGroup<CrossTU>;
 }
index 71fcf1d3929bc4e3d36945813f5d1f34db66ab00..6ba6c19a28c2ca9c928bf1d0ac56a0dd6e16d0cf 100644 (file)
@@ -1041,3 +1041,6 @@ def ExperimentalISel : DiagGroup<"experimental-isel">;
 def FunctionMultiVersioning : DiagGroup<"function-multiversion">;
 
 def NoDeref : DiagGroup<"noderef">;
+
+// A group for cross translation unit static analysis related warnings.
+def CrossTU : DiagGroup<"ctu">;
index 9a09956bc78def0ebd712f17dccc2efe993d65d9..b5371a6de73be1dda4d0d55f7b1a17aba7bc5fa8 100644 (file)
@@ -41,7 +41,9 @@ enum class index_error_code {
   missing_definition,
   failed_import,
   failed_to_get_external_ast,
-  failed_to_generate_usr
+  failed_to_generate_usr,
+  triple_mismatch,
+  lang_mismatch
 };
 
 class IndexError : public llvm::ErrorInfo<IndexError> {
@@ -50,16 +52,25 @@ public:
   IndexError(index_error_code C) : Code(C), LineNo(0) {}
   IndexError(index_error_code C, std::string FileName, int LineNo = 0)
       : Code(C), FileName(std::move(FileName)), LineNo(LineNo) {}
+  IndexError(index_error_code C, std::string FileName, std::string TripleToName,
+             std::string TripleFromName)
+      : Code(C), FileName(std::move(FileName)),
+        TripleToName(std::move(TripleToName)),
+        TripleFromName(std::move(TripleFromName)) {}
   void log(raw_ostream &OS) const override;
   std::error_code convertToErrorCode() const override;
   index_error_code getCode() const { return Code; }
   int getLineNum() const { return LineNo; }
   std::string getFileName() const { return FileName; }
+  std::string getTripleToName() const { return TripleToName; }
+  std::string getTripleFromName() const { return TripleFromName; }
 
 private:
   index_error_code Code;
   std::string FileName;
   int LineNo;
+  std::string TripleToName;
+  std::string TripleFromName;
 };
 
 /// This function parses an index file that determines which
index ec8ac6498ff9353d33bb59f64c77565549dbf66d..f49db3a8bf6ae386f16700efc57a1b8c57d7f6ce 100644 (file)
@@ -33,6 +33,7 @@ namespace clang {
 namespace cross_tu {
 
 namespace {
+
 #define DEBUG_TYPE "CrossTranslationUnit"
 STATISTIC(NumGetCTUCalled, "The # of getCTUDefinition function called");
 STATISTIC(
@@ -41,6 +42,37 @@ STATISTIC(
 STATISTIC(NumGetCTUSuccess,
           "The # of getCTUDefinition successfully returned the "
           "requested function's body");
+STATISTIC(NumTripleMismatch, "The # of triple mismatches");
+STATISTIC(NumLangMismatch, "The # of language mismatches");
+
+// Same as Triple's equality operator, but we check a field only if that is
+// known in both instances.
+bool hasEqualKnownFields(const llvm::Triple &Lhs, const llvm::Triple &Rhs) {
+  using llvm::Triple;
+  if (Lhs.getArch() != Triple::UnknownArch &&
+      Rhs.getArch() != Triple::UnknownArch && Lhs.getArch() != Rhs.getArch())
+    return false;
+  if (Lhs.getSubArch() != Triple::NoSubArch &&
+      Rhs.getSubArch() != Triple::NoSubArch &&
+      Lhs.getSubArch() != Rhs.getSubArch())
+    return false;
+  if (Lhs.getVendor() != Triple::UnknownVendor &&
+      Rhs.getVendor() != Triple::UnknownVendor &&
+      Lhs.getVendor() != Rhs.getVendor())
+    return false;
+  if (!Lhs.isOSUnknown() && !Rhs.isOSUnknown() &&
+      Lhs.getOS() != Rhs.getOS())
+    return false;
+  if (Lhs.getEnvironment() != Triple::UnknownEnvironment &&
+      Rhs.getEnvironment() != Triple::UnknownEnvironment &&
+      Lhs.getEnvironment() != Rhs.getEnvironment())
+    return false;
+  if (Lhs.getObjectFormat() != Triple::UnknownObjectFormat &&
+      Rhs.getObjectFormat() != Triple::UnknownObjectFormat &&
+      Lhs.getObjectFormat() != Rhs.getObjectFormat())
+    return false;
+  return true;
+}
 
 // FIXME: This class is will be removed after the transition to llvm::Error.
 class IndexErrorCategory : public std::error_category {
@@ -65,6 +97,10 @@ public:
       return "Failed to load external AST source.";
     case index_error_code::failed_to_generate_usr:
       return "Failed to generate USR.";
+    case index_error_code::triple_mismatch:
+      return "Triple mismatch";
+    case index_error_code::lang_mismatch:
+      return "Language mismatch";
     }
     llvm_unreachable("Unrecognized index_error_code.");
   }
@@ -179,6 +215,31 @@ CrossTranslationUnitContext::getCrossTUDefinition(const FunctionDecl *FD,
   assert(&Unit->getFileManager() ==
          &Unit->getASTContext().getSourceManager().getFileManager());
 
+  const llvm::Triple &TripleTo = Context.getTargetInfo().getTriple();
+  const llvm::Triple &TripleFrom =
+      Unit->getASTContext().getTargetInfo().getTriple();
+  // The imported AST had been generated for a different target.
+  // Some parts of the triple in the loaded ASTContext can be unknown while the
+  // very same parts in the target ASTContext are known. Thus we check for the
+  // known parts only.
+  if (!hasEqualKnownFields(TripleTo, TripleFrom)) {
+    // TODO: Pass the SourceLocation of the CallExpression for more precise
+    // diagnostics.
+    ++NumTripleMismatch;
+    return llvm::make_error<IndexError>(index_error_code::triple_mismatch,
+                                        Unit->getMainFileName(), TripleTo.str(),
+                                        TripleFrom.str());
+  }
+
+  const auto &LangTo = Context.getLangOpts();
+  const auto &LangFrom = Unit->getASTContext().getLangOpts();
+  // FIXME: Currenty we do not support CTU across C++ and C and across
+  // different dialects of C++.
+  if (LangTo.CPlusPlus != LangFrom.CPlusPlus) {
+    ++NumLangMismatch;
+    return llvm::make_error<IndexError>(index_error_code::lang_mismatch);
+  }
+
   TranslationUnitDecl *TU = Unit->getASTContext().getTranslationUnitDecl();
   if (const FunctionDecl *ResultDecl =
           findFunctionInDeclContext(TU, LookupFnName))
@@ -200,6 +261,10 @@ void CrossTranslationUnitContext::emitCrossTUDiagnostics(const IndexError &IE) {
     Context.getDiagnostics().Report(diag::err_multiple_def_index)
         << IE.getLineNum();
     break;
+  case index_error_code::triple_mismatch:
+    Context.getDiagnostics().Report(diag::warn_ctu_incompat_triple)
+        << IE.getFileName() << IE.getTripleToName() << IE.getTripleFromName();
+    break;
   default:
     break;
   }
diff --git a/test/Analysis/ctu-different-triples.cpp b/test/Analysis/ctu-different-triples.cpp
new file mode 100644 (file)
index 0000000..314bada
--- /dev/null
@@ -0,0 +1,20 @@
+// RUN: rm -rf %t && mkdir %t
+// RUN: mkdir -p %t/ctudir
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu \
+// RUN:   -emit-pch -o %t/ctudir/ctu-other.cpp.ast %S/Inputs/ctu-other.cpp
+// RUN: cp %S/Inputs/ctu-other.cpp.externalFnMap.txt %t/ctudir/externalFnMap.txt
+// RUN: %clang_analyze_cc1 -triple powerpc64-montavista-linux-gnu \
+// RUN:   -analyzer-checker=core,debug.ExprInspection \
+// RUN:   -analyzer-config experimental-enable-naive-ctu-analysis=true \
+// RUN:   -analyzer-config ctu-dir=%t/ctudir \
+// RUN:   -Werror=ctu \
+// RUN:   -verify %s
+
+// We expect an error in this file, but without a location.
+// expected-error-re@./ctu-different-triples.cpp:*{{imported AST from {{.*}} had been generated for a different target, current: powerpc64-montavista-linux-gnu, imported: x86_64-pc-linux-gnu}}
+
+int f(int);
+
+int main() {
+  return f(5);
+}
diff --git a/test/Analysis/ctu-unknown-parts-in-triples.cpp b/test/Analysis/ctu-unknown-parts-in-triples.cpp
new file mode 100644 (file)
index 0000000..a632cfb
--- /dev/null
@@ -0,0 +1,22 @@
+// We do not expect any error when one part of the triple is unknown, but other
+// known parts are equal.
+
+// RUN: rm -rf %t && mkdir %t
+// RUN: mkdir -p %t/ctudir
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu \
+// RUN:   -emit-pch -o %t/ctudir/ctu-other.cpp.ast %S/Inputs/ctu-other.cpp
+// RUN: cp %S/Inputs/ctu-other.cpp.externalFnMap.txt %t/ctudir/externalFnMap.txt
+// RUN: %clang_analyze_cc1 -triple x86_64-unknown-linux-gnu \
+// RUN:   -analyzer-checker=core,debug.ExprInspection \
+// RUN:   -analyzer-config experimental-enable-naive-ctu-analysis=true \
+// RUN:   -analyzer-config ctu-dir=%t/ctudir \
+// RUN:   -Werror=ctu \
+// RUN:   -verify %s
+
+// expected-no-diagnostics
+
+int f(int);
+
+int main() {
+  return f(5);
+}