Browse Source

fileapi: Support multiple backtraces for language standard

Justin Goshi 5 years ago
parent
commit
2f383d852d

+ 55 - 14
Source/cmFileAPICodemodel.cxx

@@ -175,6 +175,38 @@ public:
   }
 };
 
+template <typename T>
+class JBTs
+{
+public:
+  JBTs(T v = T(), std::vector<JBTIndex> ids = std::vector<JBTIndex>())
+    : Value(std::move(v))
+    , Backtraces(std::move(ids))
+  {
+  }
+  T Value;
+  std::vector<JBTIndex> Backtraces;
+  friend bool operator==(JBTs<T> const& l, JBTs<T> const& r)
+  {
+    if ((l.Value == r.Value) && (l.Backtraces.size() == r.Backtraces.size())) {
+      for (size_t i = 0; i < l.Backtraces.size(); i++) {
+        if (l.Backtraces[i].Index != r.Backtraces[i].Index) {
+          return false;
+        }
+      }
+    }
+    return true;
+  }
+  static bool ValueEq(JBTs<T> const& l, JBTs<T> const& r)
+  {
+    return l.Value == r.Value;
+  }
+  static bool ValueLess(JBTs<T> const& l, JBTs<T> const& r)
+  {
+    return l.Value < r.Value;
+  }
+};
+
 class BacktraceData
 {
   std::string TopSource;
@@ -277,7 +309,7 @@ struct CompileData
 
   std::string Language;
   std::string Sysroot;
-  JBT<std::string> LanguageStandard;
+  JBTs<std::string> LanguageStandard;
   std::vector<JBT<std::string>> Flags;
   std::vector<JBT<std::string>> Defines;
   std::vector<JBT<std::string>> PrecompileHeaders;
@@ -323,8 +355,10 @@ struct hash<CompileData>
         hash<Json::ArrayIndex>()(i.Backtrace.Index);
     }
     if (!in.LanguageStandard.Value.empty()) {
-      result = result ^ hash<std::string>()(in.LanguageStandard.Value) ^
-        hash<Json::ArrayIndex>()(in.LanguageStandard.Backtrace.Index);
+      result = result ^ hash<std::string>()(in.LanguageStandard.Value);
+      for (JBTIndex backtrace : in.LanguageStandard.Backtraces) {
+        result = result ^ hash<Json::ArrayIndex>()(backtrace.Index);
+      }
     }
     return result;
   }
@@ -369,6 +403,16 @@ class Target
     return JBT<T>(bt.Value, this->Backtraces.Add(bt.Backtrace));
   }
 
+  template <typename T>
+  JBTs<T> ToJBTs(BTs<T> const& bts)
+  {
+    std::vector<JBTIndex> ids;
+    for (cmListFileBacktrace const& backtrace : bts.Backtraces) {
+      ids.emplace_back(this->Backtraces.Add(backtrace));
+    }
+    return JBTs<T>(bts.Value, ids);
+  }
+
   void ProcessLanguages();
   void ProcessLanguage(std::string const& lang);
 
@@ -383,7 +427,7 @@ class Target
   Json::Value DumpCompileData(CompileData const& cd);
   Json::Value DumpInclude(CompileData::IncludeEntry const& inc);
   Json::Value DumpPrecompileHeader(JBT<std::string> const& header);
-  Json::Value DumpLanguageStandard(JBT<std::string> const& standard);
+  Json::Value DumpLanguageStandard(JBTs<std::string> const& standard);
   Json::Value DumpDefine(JBT<std::string> const& def);
   Json::Value DumpSources();
   Json::Value DumpSource(cmGeneratorTarget::SourceAndKind const& sk,
@@ -845,10 +889,10 @@ void Target::ProcessLanguage(std::string const& lang)
   for (BT<std::string> const& pch : precompileHeaders) {
     cd.PrecompileHeaders.emplace_back(this->ToJBT(pch));
   }
-  BT<std::string> const* languageStandard =
+  BTs<std::string> const* languageStandard =
     this->GT->GetLanguageStandardProperty(lang, this->Config);
   if (languageStandard) {
-    cd.LanguageStandard = this->ToJBT(*languageStandard);
+    cd.LanguageStandard = this->ToJBTs(*languageStandard);
   }
 }
 
@@ -1195,18 +1239,15 @@ Json::Value Target::DumpPrecompileHeader(JBT<std::string> const& header)
   return precompileHeader;
 }
 
-Json::Value Target::DumpLanguageStandard(JBT<std::string> const& standard)
+Json::Value Target::DumpLanguageStandard(JBTs<std::string> const& standard)
 {
   Json::Value languageStandard = Json::objectValue;
   languageStandard["standard"] = standard.Value;
-  if (standard.Backtrace) {
-    // Only one backtrace is currently stored for a given language standard,
-    // but we represent this as an array because it's possible for multiple
-    // compile features to set the same language standard value. Representing
-    // this as an array will allow things to just work once we support storing
-    // multiple backtraces for a language standard value.
+  if (!standard.Backtraces.empty()) {
     Json::Value backtraces = Json::arrayValue;
-    backtraces.append(standard.Backtrace.Index);
+    for (JBTIndex backtrace : standard.Backtraces) {
+      backtraces.append(backtrace.Index);
+    }
     languageStandard["backtraces"] = backtraces;
   }
   return languageStandard;

+ 12 - 7
Source/cmGeneratorTarget.cxx

@@ -949,7 +949,7 @@ bool cmGeneratorTarget::HasExplicitObjectName(cmSourceFile const* file) const
   return it != this->ExplicitObjectName.end();
 }
 
-BT<std::string> const* cmGeneratorTarget::GetLanguageStandardProperty(
+BTs<std::string> const* cmGeneratorTarget::GetLanguageStandardProperty(
   std::string const& lang, std::string const& config) const
 {
   std::string key = cmStrCat(cmSystemTools::UpperCase(config), '-', lang);
@@ -965,7 +965,7 @@ BT<std::string> const* cmGeneratorTarget::GetLanguageStandardProperty(
 cmProp cmGeneratorTarget::GetLanguageStandard(std::string const& lang,
                                               std::string const& config) const
 {
-  BT<std::string> const* languageStandard =
+  BTs<std::string> const* languageStandard =
     this->GetLanguageStandardProperty(lang, config);
 
   if (languageStandard) {
@@ -4486,8 +4486,13 @@ bool cmGeneratorTarget::ComputeCompileFeatures(std::string const& config) const
     }
 
     if (!newRequiredStandard.empty()) {
-      this->LanguageStandardMap[key] =
-        BT<std::string>(newRequiredStandard, f.Backtrace);
+      BTs<std::string>& languageStandardProperty =
+        this->LanguageStandardMap[key];
+      if (languageStandardProperty.Value != newRequiredStandard) {
+        languageStandardProperty.Value = newRequiredStandard;
+        languageStandardProperty.Backtraces.clear();
+      }
+      languageStandardProperty.Backtraces.emplace_back(f.Backtrace);
     }
   }
 
@@ -4498,14 +4503,14 @@ bool cmGeneratorTarget::ComputeCompileFeatures(
   std::string const& config, std::set<LanguagePair> const& languagePairs) const
 {
   for (const auto& language : languagePairs) {
-    BT<std::string> const* generatorTargetLanguageStandard =
+    BTs<std::string> const* generatorTargetLanguageStandard =
       this->GetLanguageStandardProperty(language.first, config);
     if (!generatorTargetLanguageStandard) {
       // If the standard isn't explicitly set we copy it over from the
       // specified paired language.
       std::string key =
         cmStrCat(cmSystemTools::UpperCase(config), '-', language.first);
-      BT<std::string> const* standardToCopy =
+      BTs<std::string> const* standardToCopy =
         this->GetLanguageStandardProperty(language.second, config);
       if (standardToCopy != nullptr) {
         this->LanguageStandardMap[key] = *standardToCopy;
@@ -4514,7 +4519,7 @@ bool cmGeneratorTarget::ComputeCompileFeatures(
         cmProp defaultStandard = this->Makefile->GetDef(
           cmStrCat("CMAKE_", language.second, "_STANDARD_DEFAULT"));
         if (defaultStandard != nullptr) {
-          this->LanguageStandardMap[key] = BT<std::string>(*defaultStandard);
+          this->LanguageStandardMap[key] = BTs<std::string>(*defaultStandard);
           generatorTargetLanguageStandard = &this->LanguageStandardMap[key];
         }
       }

+ 2 - 2
Source/cmGeneratorTarget.h

@@ -148,7 +148,7 @@ public:
   bool HasExplicitObjectName(cmSourceFile const* file) const;
   void AddExplicitObjectName(cmSourceFile const* sf);
 
-  BT<std::string> const* GetLanguageStandardProperty(
+  BTs<std::string> const* GetLanguageStandardProperty(
     std::string const& lang, std::string const& config) const;
 
   cmProp GetLanguageStandard(std::string const& lang,
@@ -1053,7 +1053,7 @@ private:
   bool GetRPATH(const std::string& config, const std::string& prop,
                 std::string& rpath) const;
 
-  mutable std::map<std::string, BT<std::string>> LanguageStandardMap;
+  mutable std::map<std::string, BTs<std::string>> LanguageStandardMap;
 
   cmProp GetPropertyWithPairedLanguageSupport(std::string const& lang,
                                               const char* suffix) const;

+ 5 - 1
Source/cmStandardLevelResolver.cxx

@@ -58,7 +58,11 @@ struct StanardLevelComputer
                               std::string& newRequiredStandard,
                               std::string* error) const
   {
-    newRequiredStandard.clear();
+    if (currentLangStandardValue) {
+      newRequiredStandard = *currentLangStandardValue;
+    } else {
+      newRequiredStandard.clear();
+    }
 
     auto needed = this->HighestStandardNeeded(makefile, feature);
 

+ 10 - 5
Source/cmTarget.cxx

@@ -186,7 +186,7 @@ public:
   std::vector<cmInstallTargetGenerator*> InstallGenerators;
   std::set<std::string> SystemIncludeDirectories;
   cmTarget::LinkLibraryVectorType OriginalLinkLibraries;
-  std::map<std::string, BT<std::string>> LanguageStandardProperties;
+  std::map<std::string, BTs<std::string>> LanguageStandardProperties;
   std::vector<std::string> IncludeDirectoriesEntries;
   std::vector<cmListFileBacktrace> IncludeDirectoriesBacktraces;
   std::vector<std::string> CompileOptionsEntries;
@@ -600,7 +600,7 @@ cmGlobalGenerator* cmTarget::GetGlobalGenerator() const
   return impl->Makefile->GetGlobalGenerator();
 }
 
-BT<std::string> const* cmTarget::GetLanguageStandardProperty(
+BTs<std::string> const* cmTarget::GetLanguageStandardProperty(
   const std::string& propertyName) const
 {
   auto entry = impl->LanguageStandardProperties.find(propertyName);
@@ -625,8 +625,13 @@ void cmTarget::SetLanguageStandardProperty(std::string const& lang,
     }
   }
 
-  impl->LanguageStandardProperties[cmStrCat(lang, "_STANDARD")] =
-    BT<std::string>(value, featureBacktrace);
+  BTs<std::string>& languageStandardProperty =
+    impl->LanguageStandardProperties[cmStrCat(lang, "_STANDARD")];
+  if (languageStandardProperty.Value != value) {
+    languageStandardProperty.Value = value;
+    languageStandardProperty.Backtraces.clear();
+  }
+  languageStandardProperty.Backtraces.emplace_back(featureBacktrace);
 }
 
 void cmTarget::AddUtility(std::string const& name, bool cross, cmMakefile* mf)
@@ -1357,7 +1362,7 @@ void cmTarget::SetProperty(const std::string& prop, const char* value)
              prop == propOBJCXX_STANDARD) {
     if (value) {
       impl->LanguageStandardProperties[prop] =
-        BT<std::string>(value, impl->Makefile->GetBacktrace());
+        BTs<std::string>(value, impl->Makefile->GetBacktrace());
     } else {
       impl->LanguageStandardProperties.erase(prop);
     }

+ 1 - 1
Source/cmTarget.h

@@ -236,7 +236,7 @@ public:
   void AddSystemIncludeDirectories(std::set<std::string> const& incs);
   std::set<std::string> const& GetSystemIncludeDirectories() const;
 
-  BT<std::string> const* GetLanguageStandardProperty(
+  BTs<std::string> const* GetLanguageStandardProperty(
     const std::string& propertyName) const;
 
   void SetLanguageStandardProperty(std::string const& lang,

+ 16 - 2
Tests/RunCMake/FileAPI/codemodel-v2-data/targets/cxx_standard_compile_feature_exe_languagestandard.json

@@ -15,8 +15,22 @@
                   "command": null,
                   "hasParent": false
               }
+          ],
+          [
+              {
+                  "file": "^cxx/CMakeLists\\.txt$",
+                  "line": 30,
+                  "command": "target_compile_features",
+                  "hasParent": true
+              },
+              {
+                  "file": "^cxx/CMakeLists\\.txt$",
+                  "line": null,
+                  "command": null,
+                  "hasParent": false
+              }
           ]
-        ],
-        "standard" : "11"
+      ],
+      "standard" : "11"
     }
 }

+ 1 - 0
Tests/RunCMake/FileAPI/cxx/CMakeLists.txt

@@ -27,5 +27,6 @@ add_executable(cxx_standard_compile_feature_exe ../empty.cxx)
 set_property(TARGET cxx_standard_compile_feature_exe PROPERTY CXX_STANDARD 98)
 if(CMAKE_CXX_STANDARD_DEFAULT AND DEFINED CMAKE_CXX11_STANDARD_COMPILE_OPTION)
   target_compile_features(cxx_standard_compile_feature_exe PRIVATE cxx_std_11)
+  target_compile_features(cxx_standard_compile_feature_exe PRIVATE cxx_decltype)
   file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/cxx_std_11.txt" "")
 endif()