From a11d9043832fdb5840f211cf16700e560a07255f Mon Sep 17 00:00:00 2001
From: Danilo Piparo <danilo.piparo@cern.ch>
Date: Fri, 23 Nov 2018 13:32:56 +0100
Subject: [PATCH] [TCling][ROOT-9660] Do not fwd declare on library load enums
 Cling knows already

the fix consists in a rewrite of the parser of enum fwd declarations which come
from dictionaries. Those are created by Cling's forward declarator.
The previous implementation was assuming namespace declarations and enum fwd
declarations on different lines, e.g.

namespace mystuff{
enum  __attribute__((annotate("$clingAutoload$myenum.h"))) myenum : unsigned int;
}

while in reality the declaration looks like
namespace mystuff{enum  __attribute__((annotate("$clingAutoload$myenum.h"))) myenum : unsigned int;}
---
 core/metacling/src/TCling.cxx | 35 ++++++++++++++++++++++++-----------
 1 file changed, 24 insertions(+), 11 deletions(-)

diff --git a/core/metacling/src/TCling.cxx b/core/metacling/src/TCling.cxx
index b4e702085ee..95268a24a91 100644
--- a/core/metacling/src/TCling.cxx
+++ b/core/metacling/src/TCling.cxx
@@ -1871,25 +1871,37 @@ void TCling::RegisterModule(const char* modulename,
          // declaration exists yet.
          std::string fwdDeclsLine;
          std::istringstream fwdDeclsCodeStr(fwdDeclsCode);
-         std::vector<std::string> scope;
+         std::vector<std::string> scopes;
          while (std::getline(fwdDeclsCodeStr, fwdDeclsLine)) {
-            if (fwdDeclsLine.find("namespace ") == 0
-                || fwdDeclsLine.find("inline namespace ") == 0) {
-               // skip leading "namespace ", trailing " {"
-               scope.push_back(fwdDeclsLine.substr(10,
-                                                   fwdDeclsLine.length() - 10 - 2));
-            } else if (fwdDeclsLine == "}") {
-               scope.pop_back();
-            } else if (fwdDeclsLine.find("enum  __attribute__((annotate(\"") == 0) {
+            const auto enumPos = fwdDeclsLine.find("enum  __attribute__((annotate(\"");
+            // We check if the line contains a fwd declaration of an enum
+            if (enumPos != std::string::npos) {
+               // We clear the scopes which we may have carried from a previous iteration
+               scopes.clear();
+               // We check if the enum is not in a scope. If yes, save its name
+               // and the names of the enclosing scopes.
+               if (enumPos != 0) {
+                  // it's enclosed in namespaces. We need to understand what they are
+                  auto nsPos = fwdDeclsLine.find("namespace");
+                  R__ASSERT(nsPos < enumPos && "Inconsistent enum and enclosing scope parsing!");
+                  while (nsPos < enumPos && nsPos != std::string::npos) {
+                     // we have a namespace, let's put it in the collection of scopes
+                     const auto nsNameStart = nsPos + 10;
+                     const auto nsNameEnd = fwdDeclsLine.find('{', nsNameStart) - nsNameStart;
+                     const auto nsName = fwdDeclsLine.substr(nsNameStart, nsNameEnd);
+                     scopes.push_back(nsName);
+                     nsPos = fwdDeclsLine.find("namespace", nsNameEnd);
+                  }
+               }
                clang::DeclContext* DC = 0;
-               for (auto &&aScope: scope) {
+               for (auto &&aScope: scopes) {
                   DC = cling::utils::Lookup::Namespace(&fInterpreter->getSema(), aScope.c_str(), DC);
                   if (!DC) {
                      // No decl context means we have to fwd declare the enum.
                      break;
                   }
                }
-               if (scope.empty() || DC) {
+               if (scopes.empty() || DC) {
                   // We know the scope; let's look for the enum.
                   size_t posEnumName = fwdDeclsLine.find("\"))) ", 32);
                   R__ASSERT(posEnumName != std::string::npos && "Inconsistent enum fwd decl!");
@@ -1916,6 +1928,7 @@ void TCling::RegisterModule(const char* modulename,
                   }
                }
             }
+
             fwdDeclsCodeLessEnums += fwdDeclsLine + "\n";
          }
       }
-- 
GitLab