Skip to content
Snippets Groups Projects
RTTITable.cpp 205.77 KiB
/**************************************************************************/
/*                                                                        */
/*  This file is part of Frama-Clang                                      */
/*                                                                        */
/*  Copyright (C) 2012-2018                                               */
/*    CEA (Commissariat à l'énergie atomique et aux énergies              */
/*         alternatives)                                                  */
/*                                                                        */
/*  you can redistribute it and/or modify it under the terms of the GNU   */
/*  Lesser General Public License as published by the Free Software       */
/*  Foundation, version 2.1.                                              */
/*                                                                        */
/*  It is distributed in the hope that it will be useful,                 */
/*  but WITHOUT ANY WARRANTY; without even the implied warranty of        */
/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         */
/*  GNU Lesser General Public License for more details.                   */
/*                                                                        */
/*  See the GNU Lesser General Public License version 2.1                 */
/*  for more details (enclosed in the file LICENSE).                      */
/*                                                                        */
/**************************************************************************/

//
// Description:
//   Implementation of pointers for Virtual Method Tables
//

#include "RTTITable.h"
#include "llvm/Support/raw_ostream.h"
#include "clang/AST/DeclTemplate.h"

bool
RTTITable::ClassInfo::hasSameSignature(
  const clang::CXXMethodDecl* first,
  const clang::CXXMethodDecl* second) const
{ if (first->isConst() != second->isConst())
    return false;
  if (first->param_size() != second->param_size())
    return false;
  if (first->getReturnType().getCanonicalType()
      != second->getReturnType().getCanonicalType())
    return false;
  
  clang::FunctionDecl::param_const_iterator paramFirstIterEnd
    = first->param_end();
  clang::FunctionDecl::param_const_iterator paramFirstIter
    = first->param_begin();
  clang::FunctionDecl::param_const_iterator paramSecondIter
    = second->param_begin();
  while (paramFirstIter != paramFirstIterEnd) {
    if ((*paramFirstIter)->getType().getCanonicalType()
        != (*paramSecondIter)->getType().getCanonicalType())
      return false;
    ++paramFirstIter;
    ++paramSecondIter;
  };
  return true;
}

int
RTTITable::ClassInfo::addDerivation(const ClassInfo& source,
    const clang::CXXRecordDecl* base, bool isVirtual)
{ int oldPosition = _virtualMethodTable.size();
  bool isFirst = _derivationsPosition.empty();
  if (!isVirtual)
    // update _derivationsPosition
    _derivationsPosition.push_back(std::make_pair(base, oldPosition));

  // update _firstMultiplePosition
  if (_firstMultiplePosition == 0) {
    if (oldPosition > 0)
      _firstMultiplePosition = oldPosition;
    else if (!source._virtualMethodTable.empty()
          || !source._virtualBaseClassTable.empty()) {
      if (!isFirst || !source.hasPvmtAsFirstField()) {
        _firstMultiplePosition = -1;
        _pvmtAccess = source._pvmtAccess;
        _pvmtAccess.push_back(std::make_pair(base, 0 /* oldPosition */));
      };
    };
  };

  if (isVirtual) {
    // update _virtualBaseClassTable and _virtualDerivationsPosition
    std::vector<const clang::CXXRecordDecl*>::const_iterator
      iter = _virtualBaseClassTable.begin(),
      iterEnd = _virtualBaseClassTable.end();
    for (; iter != iterEnd; ++iter)
      if (base == *iter)
        break;
    if (iter == iterEnd) {
      _virtualBaseClassTable.push_back(base);
      _virtualDerivationsPosition.push_back(oldPosition);
    };

    // update _virtualMethodTable
    _virtualMethodTable.push_back(VirtualMethodInfo());
    _virtualMethodTable.back().setVirtualInherits(base, oldPosition);
  };

  // merge _virtualBaseClassTable and _virtualDerivationsPosition
  //    with source._virtualBaseClassTable and source._virtualBaseClassTable
  { std::vector<const clang::CXXRecordDecl*>::const_iterator
      sourceIter = source._virtualBaseClassTable.begin(),
      sourceIterEnd = source._virtualBaseClassTable.end();
    int sourceIndex = 0;
    for (; sourceIter != sourceIterEnd; ++sourceIter) {
      std::vector<const clang::CXXRecordDecl*>::const_iterator
        iter = _virtualBaseClassTable.begin(),
        iterEnd = _virtualBaseClassTable.end();
      bool hasFound = false;
      for (; !hasFound && iter != iterEnd; ++iter)
        hasFound = *iter == *sourceIter;
      if (!hasFound) {
        _virtualBaseClassTable.push_back(*sourceIter);
        int position = oldPosition
          + source._virtualDerivationsPosition[sourceIndex];
        _virtualDerivationsPosition.push_back(!isVirtual
            ? position : (position+1));
      };
      ++sourceIndex;
    };
  };

  // update _virtualMethodTable
  std::vector<VirtualMethodInfo>::const_iterator
    iter = source._virtualMethodTable.begin(),
    iterEnd = source._virtualMethodTable.end();
  for (; iter != iterEnd; iter++) {
    VirtualMethodInfo vmi = VirtualMethodInfo(*iter);
    if (!isVirtual)
      vmi.addInherits(base, oldPosition);
    else
      vmi.setVirtualInherits(base, oldPosition);
    _virtualMethodTable.insert(_virtualMethodTable.end(), vmi);
  }
  return oldPosition;
}

int
RTTITable::ClassInfo::getBasePosition(const clang::CXXRecordDecl* base,
    bool& isVirtual) const
{ { std::vector<const clang::CXXRecordDecl*>::const_iterator
      iter = _virtualBaseClassTable.begin(),
      iterEnd = _virtualBaseClassTable.end();
    int virtualBaseIndex = -1;
    isVirtual = false;
    for (; !isVirtual && iter != iterEnd; ++iter) {
      ++virtualBaseIndex;
      isVirtual = *iter == base;
    };
    if (isVirtual) {
      assert(virtualBaseIndex < (int) _virtualDerivationsPosition.size());
      return _virtualDerivationsPosition[virtualBaseIndex];
    };
  };

  int result = 0;
  InheritancePath::const_iterator baseIterEnd = _derivationsPosition.end();
  InheritancePath::const_iterator baseIter = _derivationsPosition.begin();
  bool hasResult = false;
  for (; !hasResult && (baseIter != baseIterEnd); ++baseIter)
    if (baseIter->first == base) {
      hasResult = true;
      result = baseIter->second;
    };
  assert(hasResult);
  return result;
}

bool RTTITable::ClassInfo::isSameMethod(
  const clang::CXXMethodDecl* m1, const clang::CXXMethodDecl* m2) const {
  // in case both m1 and m2 are (virtual) destructors, we must return true,
  // as there is at most one destructor in the vmt, the one for the most
  // derived class. However, the two DeclarationName are not equal
  // because of the class name.
  // In all other cases, we just have to compare names and signatures
  const clang::DeclarationName& n1 = m1->getNameInfo().getName();
  const clang::DeclarationName& n2 = m2->getNameInfo().getName();
  bool dest = n1.getNameKind() == clang::DeclarationName::CXXDestructorName;
  dest = dest && n2.getNameKind() == clang::DeclarationName::CXXDestructorName;
  return dest || (n1 == n2 && hasSameSignature(m1,m2));
}

int
RTTITable::ClassInfo::addVirtualMethod(clang::CXXMethodDecl* method)
{ typedef std::vector<VirtualMethodInfo>::iterator MethodIterator;
  MethodIterator iterEnd = _virtualMethodTable.end();
  int result = 0, index = 0;
  bool hasFound = false;
  for (MethodIterator iter = _virtualMethodTable.begin();
      iter != iterEnd; ++iter) {
    if (iter->isMethod() && isSameMethod(iter->getMethod(), method)) {
      if (_virtualBaseClassTable.empty()
          && (_firstMultiplePosition == 0 || _firstMultiplePosition > index))
        *iter = VirtualMethodInfo(method); // erase getInheritancePath()
      else
        iter->setMethod(method);
      if (!hasFound)
        result = index;
      if (_derivationsPosition.empty()
          || _derivationsPosition.back().second <= index)
        return result;
      hasFound = true;
    };
    ++index;
  };
  if (!hasFound)
    _virtualMethodTable.push_back(VirtualMethodInfo(method));
  else
    result = index;
  return result;
}

int
RTTITable::ClassInfo::getIndexOfMethod(clang::CXXMethodDecl* method,
    const InheritancePath*& inheritancePath,
    const VirtualInheritancePath*& virtualInheritancePath) const
{ MethodIterator iterEnd = _virtualMethodTable.end();
  int result = 0;
  for (MethodIterator iter = _virtualMethodTable.begin();
      iter != iterEnd; ++iter) {
    if (iter->isMethod() && isSameMethod(iter->getMethod(), method)) {
      inheritancePath = &iter->getInheritancePath();
      if (iter->hasVirtualInheritancePath())
        virtualInheritancePath = &iter->getVirtualInheritancePath();
      return result;
    };
    ++result;
  };
  assert(false);
  return 0;
}

void
RTTITable::DelayedMethodCalls::MethodCall::apply(const Clang_utils& utils,
    const ClassInfo& methodTable)
{ assert(!_indexShiftObject.empty());
  const InheritancePath* inheritancePath = NULL;
  const VirtualInheritancePath* virtualInheritancePath = NULL;
  int methodIndex;
  if (_method)
    methodIndex = methodTable.getIndexOfMethod(_method, inheritancePath,
      virtualInheritancePath);
  else {
    assert(_base);
    bool isVirtual = false;
    methodIndex = methodTable.getBasePosition(_base, isVirtual);
    assert(isVirtual);
    //const VirtualMethodInfo& info = methodTable.beginOfMethods()[methodIndex];
    // assert(info.isVirtualBaseAccess());
    // inheritancePath = &info.getInheritancePath();
    // if (info.hasVirtualInheritancePath())
    //   virtualInheritancePath = &info.getVirtualInheritancePath();
  };
  /* inheritance */ list shiftObject = NULL;
  /* inheritance */ list shiftPvmt = NULL;
  if (_method && virtualInheritancePath) {
    tkind templateParameters =
      utils.makeTemplateKind(virtualInheritancePath->first);
    shiftObject = cons_container(inheritance_cons(
          utils.makeQualifiedName(*virtualInheritancePath->first), 
          templateParameters, PUBLIC, VVIRTUAL,
          virtualInheritancePath->second), NULL);
  };
  if (_method) {
    ForwardReferenceList shiftEnd(shiftObject);
    InheritancePath::const_iterator iterEnd = inheritancePath->end();
    for (InheritancePath::const_iterator iter = inheritancePath->begin();
        iter != iterEnd; ++iter) {
      tkind templateParameters = utils.makeTemplateKind(iter->first);
      shiftEnd.insertContainer(
        inheritance_cons(
          utils.makeQualifiedName(*iter->first), templateParameters,
          PUBLIC, VSTANDARD, iter->second));
    }

    if (!methodTable.hasPvmtAsFirstField()) {
      ForwardReferenceList shiftEnd = ForwardReferenceList(shiftPvmt);
      inheritancePath = &methodTable.getPvmtField();
      InheritancePath::const_reverse_iterator iterEnd = inheritancePath->rend(),
          iter = inheritancePath->rbegin();
      for (; iter != iterEnd; ++iter) {
        tkind templateParameters = utils.makeTemplateKind(iter->first);
        shiftEnd.insertContainer(
          inheritance_cons(
            utils.makeQualifiedName(*iter->first), templateParameters, 
            PUBLIC, VSTANDARD, 0 /* iter->second */));
      };
    };
  };

  std::vector<std::pair<int64_t*, std::pair</* inheritance */ list*,
      /* inheritance */ list*> > >::const_iterator
    iterUpdateEnd = _indexShiftObject.end(),
    iterUpdate = _indexShiftObject.begin();
  assert(iterUpdate != iterUpdateEnd);
  *iterUpdate->first = methodIndex;
  if (_method) {
    *iterUpdate->second.first = shiftObject;
    *iterUpdate->second.second = shiftPvmt;
  };
  for (++iterUpdate; iterUpdate != iterUpdateEnd; ++iterUpdate) {
    *iterUpdate->first = methodIndex;
    if (_method) {
      list* backToUpdate = iterUpdate->second.first;
      list shiftIter = shiftObject;
      while (shiftIter) {
        *backToUpdate = cons_container(inheritance_dup((inheritance)
            shiftIter->element.container), NULL);
        backToUpdate = &(*backToUpdate)->next;
        shiftIter = shiftIter->next;
      };
      if (shiftPvmt) {
        backToUpdate = iterUpdate->second.second;
        shiftIter = shiftPvmt;
        while (shiftIter) {
          *backToUpdate = cons_container(inheritance_dup((inheritance)
              shiftIter->element.container), NULL);
          backToUpdate = &(*backToUpdate)->next;
          shiftIter = shiftIter->next;
        };
      };
    };
  };
  _indexShiftObject.clear();
}

void
RTTITable::DelayedMethodCalls::addMethodCall(clang::CXXMethodDecl* method,
    int64_t* methodIndex, /* inheritance */ list* shiftObject,
    /* inheritance */ list* shiftPvmt)
{ std::vector<MethodCall>::iterator iterEnd = _delayedCalls.end();
  for (std::vector<MethodCall>::iterator iter = _delayedCalls.begin();
      iter != iterEnd; ++iter) {
    if (iter->getMethod() == method) {
      iter->add(methodIndex, shiftObject, shiftPvmt);
      return;
    };
  };
  _delayedCalls.push_back(MethodCall(method, methodIndex, shiftObject,
    shiftPvmt));
}

void
RTTITable::DelayedMethodCalls::addFieldAccess(
    clang::CXXRecordDecl* baseClass, int64_t* accessIndex)
{ std::vector<MethodCall>::iterator iterEnd = _delayedCalls.end();
  for (std::vector<MethodCall>::iterator iter = _delayedCalls.begin();
      iter != iterEnd; ++iter) {
    if (iter->getBaseAccess() == baseClass) {
      iter->add(accessIndex);
      return;
    };
  };
  _delayedCalls.push_back(MethodCall(baseClass, accessIndex));
}

void
RTTITable::DelayedMethodCalls::updateWith(const Clang_utils& utils,
    const ClassInfo& methodTable)
{ std::vector<MethodCall>::iterator iterEnd = _delayedCalls.end();
  for (std::vector<MethodCall>::iterator iter = _delayedCalls.begin();
      iter != iterEnd; ++iter)
    iter->apply(utils, methodTable);
  _delayedCalls.clear();
}

qualified_name RTTITable::specialMemberName(
  const Clang_utils& utils, const char* base) const
{
  const clang::CXXRecordDecl* currClass = _currentClass.front();
  tkind templateArgs = utils.makeTemplateKind(currClass);
  return
    utils.makeQualifiedName(currClass, strdup(base), NULL, &templateArgs);
}

void
RTTITable::insertVMTContentPrelude(ForwardReferenceList& globals, location loc)
{ 
  // struct _frama_c_vmt_content {
  //   void (*method_ptr)();
  //   int shift_this;
  // };
  { /* class_decl */ list vmtContent = NULL;
    ForwardReferenceList endVmtContent(vmtContent);
    { typ methodPtrType = typ_Pointer(pkind_PFunctionPointer(signature_cons(
          qual_type_cons(NULL, typ_Void()), NULL, true)));
      endVmtContent.insertContainer(class_decl_CFieldDecl(copy_loc(loc),
          strdup("method_ptr"), qual_type_cons(NULL, methodPtrType),
          opt_none(), false));
    }
    { endVmtContent.insertContainer(class_decl_CFieldDecl(copy_loc(loc),
          strdup("shift_this"), qual_type_cons(NULL, typ_Int(IINT)),
          opt_none(), false));
    };
    globals.insertContainer(
      translation_unit_decl_Compound(
        copy_loc(loc),
        decl_or_impl_name_Implementation(
          qualified_name_cons(NULL, strdup("_frama_c_vmt_content"))),
        CSTRUCT, opt_none(),
        opt_some_container(vmtContent),
        false, tkind_TStandard(), false, false));
  };
}

void
RTTITable::insertVMTTypePrelude(ForwardReferenceList& globals, location loc) {
  // struct _frama_c_vmt {
  //   struct _frama_c_vmt_content* table;
  //   int table_size;
  //   struct _frama_c_rtti_name_info_node* rtti_info;
  // };
  { /* class_decl */ list vmtContent = NULL;
    ForwardReferenceList endVmtContent(vmtContent);
    { typ tableType = typ_Pointer(pkind_PDataPointer(
          qual_type_cons(NULL, typ_Struct(qualified_name_cons(NULL,
            strdup("_frama_c_vmt_content")), tkind_TStandard()))));
      endVmtContent.insertContainer(class_decl_CFieldDecl(copy_loc(loc),
          strdup("table"), qual_type_cons(NULL, tableType), opt_none(), false));
    }
    { endVmtContent.insertContainer(class_decl_CFieldDecl(copy_loc(loc),
          strdup("table_size"), qual_type_cons(NULL, typ_Int(IINT)),
          opt_none(), false));
    };
    { typ rttiInfoType = typ_Pointer(pkind_PDataPointer(
          qual_type_cons(NULL, typ_Struct(qualified_name_cons(NULL,
            strdup("_frama_c_rtti_name_info_node")), tkind_TStandard()))));
      endVmtContent.insertContainer(
        class_decl_CFieldDecl(
          copy_loc(loc),
          strdup("rtti_info"),
          qual_type_cons(NULL, rttiInfoType),
          opt_none(),
          false));
    }
    globals.insertContainer(
      translation_unit_decl_Compound(
        copy_loc(loc),
        decl_or_impl_name_Implementation(
          qualified_name_cons(NULL, strdup("_frama_c_vmt"))),
        CSTRUCT, opt_none(),
        opt_some_container(vmtContent),
        false, tkind_TStandard(), false, false));
  };
}

void
RTTITable::insertRTTIInfoPrelude(ForwardReferenceList& globals, location loc) {
  // struct _frama_c_rtti_name_info_content {
  //   struct _frama_c_rtti_name_info_node* value;
  //   int shift_object; 
  //   int shift_vmt; 
  // };
  { /* class_decl */ list rttiContent = NULL;
    ForwardReferenceList endRttiContent(rttiContent);
    { typ valueType = typ_Pointer(pkind_PDataPointer(
          qual_type_cons(NULL, typ_Struct(qualified_name_cons(NULL,
              "_frama_c_rtti_name_info_node"), tkind_TStandard()))));
      endRttiContent.insertContainer(
        class_decl_CFieldDecl(
          copy_loc(loc),
          strdup("value"),
          qual_type_cons(NULL, valueType),
          opt_none(),
          false));
    }
    { endRttiContent.insertContainer(
        class_decl_CFieldDecl(
          copy_loc(loc),
          strdup("shift_object"),
          qual_type_cons(NULL, typ_Int(IINT)),
          opt_none(),
          false));
      endRttiContent.insertContainer(
        class_decl_CFieldDecl(
          copy_loc(loc),
          strdup("shift_vmt"),
          qual_type_cons(NULL, typ_Int(IINT)),
          opt_none(),
          false));
    };
    globals.insertContainer(
      translation_unit_decl_Compound(
        copy_loc(loc),
        decl_or_impl_name_Implementation(
          qualified_name_cons(NULL, strdup("_frama_c_rtti_name_info_content"))),
        CSTRUCT, opt_none(),
        opt_some_container(rttiContent),
        false, tkind_TStandard(), false, false));
  };

  // struct _frama_c_rtti_name_info_node {
  //   const char* name;
  //   struct _frama_c_rtti_name_info_content* base_classes;
  //   int number_of_base_classes;
  //   struct _frama_c_vmt* pvmt;
  // };
  { /* class_decl */ list rttiContent = NULL;
    ForwardReferenceList endRttiContent(rttiContent);
    { typ nameType = typ_Pointer(pkind_PDataPointer(
          qual_type_cons(cons_plain(CONST, NULL), typ_Int(ICHAR))));
      endRttiContent.insertContainer(
        class_decl_CFieldDecl(
          copy_loc(loc),
          strdup("name"),
          qual_type_cons(NULL, nameType),
          opt_none(),
          false));
    }
    { typ baseClassesType = typ_Pointer(pkind_PDataPointer(
          qual_type_cons(NULL, typ_Struct(qualified_name_cons(NULL,
            strdup("_frama_c_rtti_name_info_content")), tkind_TStandard()))));
      endRttiContent.insertContainer(
        class_decl_CFieldDecl(
          copy_loc(loc),
          strdup("base_classes"),
          qual_type_cons(NULL, baseClassesType),
          opt_none(),
          false));
    }
    { endRttiContent.insertContainer(
        class_decl_CFieldDecl(
          copy_loc(loc),
          strdup("number_of_base_classes"),
          qual_type_cons(NULL, typ_Int(IINT)),
          opt_none(),
          false));
    }
    { typ vmtType = typ_Pointer(pkind_PDataPointer(
          qual_type_cons(NULL, typ_Struct(qualified_name_cons(NULL,
            strdup("_frama_c_vmt")), tkind_TStandard()))));
      endRttiContent.insertContainer(
        class_decl_CFieldDecl(
          copy_loc(loc),
          strdup("pvmt"),
          qual_type_cons(NULL, vmtType),
          opt_none(),
          false));
    }
    globals.insertContainer(
      translation_unit_decl_Compound(
        copy_loc(loc),
        decl_or_impl_name_Implementation(
          qualified_name_cons(NULL, strdup("_frama_c_rtti_name_info_node"))),
        CSTRUCT, opt_none(),
        opt_some_container(rttiContent),
        false, tkind_TStandard(), false, false));
  };
}

/* statement */ list*
RTTITable::insertRTTIAlgorithmsAuxDeclPrelude(ForwardReferenceList& globals,
    location loc) {
  // int _frama_c_find_dynamic_cast_aux(
  //   struct _frama_c_rtti_name_info_node* target_info,
  //   struct _frama_c_rtti_name_info_content* concrete_base,
  //   int number_of_bases, int found_shift_object, int found_shift_vmt,
  //   int last_shift_vmt, int* shift_object, int* distance) { ... }
  /* arg_decl */ list arguments = NULL;
  decl_or_impl_name functionName = decl_or_impl_name_Implementation(
      qualified_name_cons(NULL, strdup("_frama_c_find_dynamic_cast_aux")));
  { ForwardReferenceList argumentsEnd(arguments);
    argumentsEnd.insertContainer(arg_decl_cons(
      qual_type_cons(NULL, typ_Pointer(pkind_PDataPointer(qual_type_cons(NULL,
          typ_Struct(qualified_name_cons(NULL,
              strdup("_frama_c_rtti_name_info_node")), tkind_TStandard()))))),
      strdup("target_info"), copy_loc(loc)));
    argumentsEnd.insertContainer(arg_decl_cons(
      qual_type_cons(NULL, typ_Pointer(pkind_PDataPointer(qual_type_cons(NULL,
        typ_Struct(qualified_name_cons(NULL,
            strdup("_frama_c_rtti_name_info_content")), tkind_TStandard()))))),
      strdup("concrete_base"), copy_loc(loc)));
    argumentsEnd.insertContainer(arg_decl_cons(
      qual_type_cons(NULL, typ_Int(IINT)),
      strdup("number_of_bases"), copy_loc(loc)));
    argumentsEnd.insertContainer(arg_decl_cons(
      qual_type_cons(NULL, typ_Int(IINT)),
      strdup("found_shift_object"), copy_loc(loc)));
    argumentsEnd.insertContainer(arg_decl_cons(
      qual_type_cons(NULL, typ_Int(IINT)),
      strdup("found_shift_vmt"), copy_loc(loc)));
    argumentsEnd.insertContainer(arg_decl_cons(
      qual_type_cons(NULL, typ_Int(IINT)),
      strdup("last_shift_vmt"), copy_loc(loc)));
    argumentsEnd.insertContainer(arg_decl_cons(
      qual_type_cons(NULL, typ_Pointer(pkind_PDataPointer(qual_type_cons(NULL,
          typ_Int(IINT))))), strdup("shift_object"), copy_loc(loc)));
    argumentsEnd.insertContainer(arg_decl_cons(
      qual_type_cons(NULL, typ_Pointer(pkind_PDataPointer(qual_type_cons(NULL,
          typ_Int(IINT))))), strdup("distance"), copy_loc(loc)));
  };

  option result = opt_some_container(NULL);
  globals.insertContainer(
    translation_unit_decl_Function(
      functionName, funkind_FKFunction(), copy_loc(loc),
      qual_type_cons(NULL, typ_Int(IINT)),
      arguments, result, false /* is_extern_c */,
      false /* is_ghost */,
      false /* is_variadic */,
      tkind_TStandard(),
      false /* has_further_definition */,
      opt_none() /* throws */,
      opt_none() /* fun_spec */));
  return (/* statement */ list*) &result->content.container;
}

/* statement */ list*
RTTITable::insertRTTIAlgorithmsAuxWhilePrelude(/* statement */ list*
    functionBodyRef, location loc) {
  ForwardReferenceList functionBody(*functionBodyRef);
  { functionBody.insertContainer(statement_VarDecl(copy_loc(loc),
      strdup("result"), qual_type_cons(NULL, typ_Int(IINT)),
      opt_some_container(
        init_expr_Single_init(makeIntLiteral(loc,IINT,0)))));
    functionBody.insertContainer(statement_VarDecl(copy_loc(loc),
      strdup("cursor"),
      qual_type_cons(NULL, typ_Pointer(pkind_PDataPointer(qual_type_cons(NULL,
          typ_Struct(qualified_name_cons(NULL,
              "_frama_c_rtti_name_info_content"), tkind_TStandard()))))),
      opt_some_container(init_expr_Single_init(expression_cons(copy_loc(loc),
          exp_node_Variable(variable_FunctionParameter(
              strdup("concrete_base"))))))));
    functionBody.insertContainer(statement_VarDecl(copy_loc(loc),
      strdup("is_over"), qual_type_cons(NULL, typ_Int(IINT)),
      opt_some_container(
        init_expr_Single_init(makeIntLiteral(loc,IINT,0)))));
    functionBody.insertContainer(statement_VarDecl(copy_loc(loc),
      strdup("base_index"), qual_type_cons(NULL, typ_Int(IINT)),
      opt_some_container(
        init_expr_Single_init(makeIntLiteral(loc,IINT,0)))));
  };

  /* statement */ list* result = NULL;
  //   while (base_index < number_of_bases) {
  //     ...
  //   }; /* end of while */
  { expression conditionWhile = expression_cons(copy_loc(loc),
      exp_node_Binary_operator(BOLESS, AKRVALUE,
        expression_cons(copy_loc(loc), exp_node_Variable(variable_Local(
                qualified_name_cons(NULL, strdup("base_index"))))),
        expression_cons(copy_loc(loc), exp_node_Variable(
          variable_FunctionParameter(strdup("number_of_bases"))))));
    statement body = statement_Block(copy_loc(loc), NULL);
    functionBody.insertContainer(statement_While(copy_loc(loc),
      conditionWhile, body, NULL /* annot */));
    result = (/* statement */ list*) &body->cons_statement.Block.instructions;
  };

  //   return result;
  // }
  functionBody.insertContainer(statement_Return(copy_loc(loc),
    opt_some_container(expression_cons(copy_loc(loc), exp_node_Variable(
      variable_Local(qualified_name_cons(NULL, strdup("result"))))))));
  return result;
}

//     if (cursor->value == target_info) {
//       if (*distance < 0 || *distance >= 1) {
//         ...
//       }
//     }
//     else if (cursor->shift_vmt <= found_shift_vmt && (
//       (base_index < number_of_bases-1)
//         ? ((cursor+1)->shift_vmt > found_shift_vmt)
//         : ((last_shift_vmt == -1) || (found_shift_vmt < last_shift_vmt)))) {
//       ...
//     }
//     else if (*distance < 0 || *distance > 1) {
//       ...
//     }

void
RTTITable::insertRTTIAlgorithmsAuxWhileBodyPrelude(/* statement */ list*
    whileBodyRef, location loc, /* statement */ list*& then,
    /* statement */ list*& elseThen, /* statement */ list*& elseElseThen) {
  ForwardReferenceList whileBody(*whileBodyRef);
  //     if (cursor->value == target_info) {
  //       if (*distance < 0 || *distance >= 1) {
  //         ...
  //       }
  //     }
  expression subconditionIf =
    expression_cons(
      copy_loc(loc),
      exp_node_Binary_operator(
        BOLOGICALOR, AKRVALUE,
        expression_cons(
          copy_loc(loc),
          exp_node_Binary_operator(
            BOLESS, AKRVALUE,
            expression_cons(
              copy_loc(loc),
              exp_node_Dereference(
                expression_cons(
                  copy_loc(loc),
                  exp_node_Variable(
                    variable_FunctionParameter(strdup("distance")))))),
            makeIntLiteral(loc,IINT,0))),
        expression_cons(
          copy_loc(loc),
          exp_node_Binary_operator(
            BOGREATEROREQUAL, AKRVALUE,
            expression_cons(
              copy_loc(loc),
              exp_node_Dereference(
                expression_cons(
                  copy_loc(loc),
                  exp_node_Variable(
                    variable_FunctionParameter(strdup("distance")))))),
            makeIntLiteral(loc,IINT,1)))));
  expression conditionIf = expression_cons(copy_loc(loc),
    exp_node_Binary_operator(BOEQUAL, AKRVALUE,
      expression_cons(copy_loc(loc), exp_node_FieldAccess(
        expression_cons(copy_loc(loc), exp_node_Dereference(
          expression_cons(copy_loc(loc), exp_node_Variable(variable_Local(
                  qualified_name_cons(NULL, strdup("cursor"))))))),
        strdup("value"))),
      expression_cons(copy_loc(loc), exp_node_Variable(
        variable_FunctionParameter(strdup("target_info"))))));
  statement thenBlock = statement_Block(copy_loc(loc), NULL);
  statement firstCondition =
    statement_Condition(
      copy_loc(loc),
      cond_statement_CondExpression(conditionIf),
      statement_Condition(
        copy_loc(loc),
        cond_statement_CondExpression(subconditionIf),
        thenBlock,
        statement_Nop(copy_loc(loc))),
      statement_Nop(copy_loc(loc)));
  then = (/* statement */ list*) &thenBlock->cons_statement.Block.instructions;
  whileBody.insertContainer(firstCondition);
  statement* elseStmt = &firstCondition->cons_statement.Condition
    .else_instruction;

  //     else if (cursor->shift_vmt <= found_shift_vmt && (
  //       (base_index < number_of_bases-1)
  //         ? ((cursor+1)->shift_vmt > found_shift_vmt)
  //         : ((last_shift_vmt == -1) || (found_shift_vmt < last_shift_vmt))))
  //     {
  //       ...
  //     }

  expression localFirstAndExpression =
    expression_cons(
      copy_loc(loc),
      exp_node_Binary_operator(
        BOLESSOREQUAL, AKRVALUE,
        expression_cons(
          copy_loc(loc),
          exp_node_FieldAccess(
            expression_cons(
              copy_loc(loc),
              exp_node_Dereference(
                expression_cons(
                  copy_loc(loc),
                  exp_node_Variable(
                    variable_Local(
                      qualified_name_cons(NULL, strdup("cursor"))))))),
            strdup("shift_vmt"))),
        expression_cons(
          copy_loc(loc),
          exp_node_Variable(
            variable_FunctionParameter(strdup("found_shift_vmt"))))));
  exp_node* localSecondAndNode = NULL;
  expression localSecondAndExpression = expression_cons(copy_loc(loc), NULL);
  localSecondAndNode = &localSecondAndExpression->econtent;
  statement elseThenBlock = statement_Block(copy_loc(loc), NULL);
  elseThen = (/* statement */ list*) &elseThenBlock->cons_statement.Block
    .instructions;

  *elseStmt =
      statement_Condition(
        copy_loc(loc),
        cond_statement_CondExpression(
          expression_cons(
            copy_loc(loc),
            exp_node_Binary_operator(
              BOLOGICALAND,
              AKRVALUE, localFirstAndExpression, localSecondAndExpression))),
        elseThenBlock,
        statement_Nop(copy_loc(loc)));
  statement* elseElseStmt = &(*elseStmt)->cons_statement.Condition
    .else_instruction;
  { exp_node expressionCondition =
      exp_node_Binary_operator(
        BOLESS, AKRVALUE,
        expression_cons(
          copy_loc(loc),
          exp_node_Variable(
            variable_Local(qualified_name_cons(NULL, strdup("base_index"))))),
        expression_cons(
          copy_loc(loc),
          exp_node_Binary_operator(
            BOMINUS, AKRVALUE,
            expression_cons(
              copy_loc(loc),
              exp_node_Variable(
                variable_FunctionParameter(strdup("number_of_bases")))),
            makeIntLiteral(loc,IINT,1))));
    exp_node expressionThenCondition =
      exp_node_Binary_operator(
        BOGREATER, AKRVALUE,
        expression_cons(
          copy_loc(loc),
          exp_node_FieldAccess(
            expression_cons(
              copy_loc(loc),
              exp_node_Dereference(
                expression_cons(
                  copy_loc(loc),
                  exp_node_Binary_operator(
                    BOPLUS, AKRVALUE,
                    expression_cons(
                      copy_loc(loc),
                      exp_node_Variable(
                        variable_Local(
                          qualified_name_cons(NULL, strdup("cursor"))))),
                    makeIntLiteral(loc,IINT,1))))),
            strdup("shift_vmt"))),
        expression_cons(
          copy_loc(loc),
          exp_node_Variable(
            variable_FunctionParameter(strdup("found_shift_vmt")))));
    exp_node expressionElseFirstCondition =
      exp_node_Binary_operator(
        BOEQUAL, AKRVALUE,
        expression_cons(
          copy_loc(loc),
          exp_node_Variable(
            variable_FunctionParameter(strdup("last_shift_vmt")))),
        expression_cons(
          copy_loc(loc),
          exp_node_Unary_operator(
            uokind_UOOpposite(),
            makeIntLiteral(loc,IINT,1))));
    exp_node expressionElseSecondCondition = exp_node_Binary_operator(
      BOLESS, AKRVALUE, expression_cons(copy_loc(loc), exp_node_Variable(
        variable_FunctionParameter(strdup("found_shift_vmt")))),
      expression_cons(copy_loc(loc), exp_node_Variable(
          variable_FunctionParameter(strdup("last_shift_vmt")))));
    *localSecondAndNode = exp_node_Conditional(
      expression_cons(copy_loc(loc), expressionCondition),
      expression_cons(copy_loc(loc), expressionThenCondition),
      expression_cons(copy_loc(loc), exp_node_Binary_operator(
        BOLOGICALOR, AKRVALUE,
        expression_cons(copy_loc(loc), expressionElseFirstCondition),
        expression_cons(copy_loc(loc),
          expressionElseSecondCondition))));
  };

  //     else if (*distance < 0 || *distance > 1) {
  //       ...
  //     };
  //           /* case 0 and 1 are not possible */
  exp_node* localFirstOrNode = NULL;
  expression localFirstOrExpression = expression_cons(copy_loc(loc), NULL);
  localFirstOrNode = &localFirstOrExpression->econtent;
  exp_node* localSecondOrNode = NULL;
  expression localSecondOrExpression = expression_cons(copy_loc(loc), NULL);
  localSecondOrNode = &localSecondOrExpression->econtent;
  statement elseElseThenBlock = statement_Block(copy_loc(loc), NULL);
  elseElseThen = (/* statement */ list*) &elseElseThenBlock->cons_statement
    .Block.instructions;

  *elseElseStmt = statement_Condition(copy_loc(loc),
    cond_statement_CondExpression(expression_cons(copy_loc(loc),
      exp_node_Binary_operator(BOLOGICALOR, AKRVALUE, localFirstOrExpression,
        localSecondOrExpression))),
    elseElseThenBlock, statement_Nop(copy_loc(loc)));

  *localFirstOrNode =
    exp_node_Binary_operator(
      BOLESS, AKRVALUE, 
      expression_cons(
        copy_loc(loc),
        exp_node_Dereference(
          expression_cons(
            copy_loc(loc),
            exp_node_Variable(
              variable_FunctionParameter(strdup("distance")))))),
      makeIntLiteral(loc,IINT,0));
  *localSecondOrNode =
    exp_node_Binary_operator(
      BOGREATEROREQUAL, AKRVALUE, 
      expression_cons(
        copy_loc(loc),
        exp_node_Dereference(
          expression_cons(
            copy_loc(loc),
            exp_node_Variable(
              variable_FunctionParameter(strdup("distance")))))),
      makeIntLiteral(loc,IINT,1));
  //     cursor++;
  whileBody.insertContainer(
    statement_Expression(
      copy_loc(loc),
      expression_cons(
        copy_loc(loc),
        exp_node_Unary_operator(
          uokind_UOPostInc(),
          expression_cons(
            copy_loc(loc),
            exp_node_Variable(
              variable_Local(qualified_name_cons(NULL, strdup("cursor")))))))));
  //     base_index++;
  whileBody.insertContainer(
    statement_Expression(
      copy_loc(loc),
      expression_cons(
        copy_loc(loc),
        exp_node_Unary_operator(
          uokind_UOPostInc(),
          expression_cons(
            copy_loc(loc),
            exp_node_Variable(
              variable_Local(
                qualified_name_cons(NULL, strdup("base_index")))))))));
}

void
RTTITable::insertRTTIAlgorithmsAuxWhileThenBodyPrelude(/* statement */ list*
    statements, location loc) {
  ForwardReferenceList statementsEnd(*statements);

//         if (found_shift_vmt == cursor->shift_vmt)
  expression conditionIf = expression_cons(copy_loc(loc),
    exp_node_Binary_operator(BOEQUAL, AKRVALUE,
      expression_cons(copy_loc(loc), exp_node_Variable(
          variable_FunctionParameter(strdup("found_shift_vmt")))),
      expression_cons(copy_loc(loc), exp_node_FieldAccess(
        expression_cons(copy_loc(loc), exp_node_Dereference(
        expression_cons(copy_loc(loc), exp_node_Variable(
        variable_Local(qualified_name_cons(NULL, strdup("cursor"))))))),
        strdup("shift_vmt")))));
//           *distance = 0; /* impossible case */
  statement thenFoundLocation =
    statement_Expression(
      copy_loc(loc),
      expression_cons(
        copy_loc(loc),
        exp_node_Assign(
          expression_cons(
            copy_loc(loc),
            exp_node_Dereference(
              expression_cons(
                copy_loc(loc),
                exp_node_Variable(
                  variable_Local(
                    qualified_name_cons(NULL, strdup("distance"))))))),
          makeIntLiteral(loc,IINT,0))));
//         else
//           *distance = 1;
  statement elseFoundLocation =
    statement_Expression(
      copy_loc(loc),
      expression_cons(
        copy_loc(loc),
        exp_node_Assign(
          expression_cons(
            copy_loc(loc),
            exp_node_Dereference(
              expression_cons(
                copy_loc(loc),
                exp_node_Variable(
                  variable_Local(
                    qualified_name_cons(NULL, strdup("distance"))))))),
          makeIntLiteral(loc,IINT,1))));
  statementsEnd.insertContainer(
    statement_Condition(
      copy_loc(loc),
      cond_statement_CondExpression(conditionIf),
      thenFoundLocation,
      elseFoundLocation));
//         *shift_object = found_shift_object - cursor->shift_object;
  statementsEnd.insertContainer(statement_Expression(
    copy_loc(loc), expression_cons(copy_loc(loc), exp_node_Assign(
      expression_cons(copy_loc(loc), exp_node_Dereference(
        expression_cons(copy_loc(loc), exp_node_Variable(
          variable_FunctionParameter(strdup("shift_object")))))),
      expression_cons(copy_loc(loc), exp_node_Binary_operator(BOMINUS, AKRVALUE,
        expression_cons(copy_loc(loc), exp_node_Variable(variable_Local(
          qualified_name_cons(NULL, strdup("found_shift_object"))))),
        expression_cons(copy_loc(loc), exp_node_FieldAccess(
          expression_cons(copy_loc(loc), exp_node_Dereference(
            expression_cons(copy_loc(loc), exp_node_Variable(
              variable_Local(qualified_name_cons(NULL, strdup("cursor"))))))),
                strdup("shift_object")))))))));
//         result = 1;
  statementsEnd.insertContainer(
    statement_Expression(
      copy_loc(loc),
      expression_cons(
        copy_loc(loc),
        exp_node_Assign(
          expression_cons(
            copy_loc(loc),
            exp_node_Variable(
              variable_Local(qualified_name_cons(NULL, strdup("result"))))),
          makeIntLiteral(loc,IINT,1)))));
}

void
RTTITable::insertRTTIAlgorithmsAuxWhileElseThenBodyPrelude(/* statement */ list*
    statements, location loc) {
  ForwardReferenceList statementsEnd(*statements);
  //       int local_distance = 0;
  statementsEnd.insertContainer(
    statement_VarDecl(
      copy_loc(loc),
      strdup("local_distance"),
      qual_type_cons(NULL, typ_Int(IINT)),
      opt_some_container(
        init_expr_Single_init(makeIntLiteral(loc,IINT,0)))));
  //       int local_shift_object = 0;
  statementsEnd.insertContainer(
    statement_VarDecl(
      copy_loc(loc),
      strdup("local_shift_object"),
      qual_type_cons(NULL, typ_Int(IINT)),
      opt_some_container(
        init_expr_Single_init(makeIntLiteral(loc,IINT,0)))));
  //       int local_result = _frama_c_find_dynamic_cast_aux(target_info,
  //         cursor->value->base_classes,
  //         cursor->value->number_of_base_classes,
  //         found_shift_object - cursor->shift_object,
  //         found_shift_vmt - cursor->shift_vmt,
  //         (base_index < number_of_bases-1) ? (cursor+1)->shift_vmt
  //                                          : last_shift_vmt,
  //         &local_shift_object, &local_distance);

  /* qual_type */ list parameters = NULL;
  ForwardReferenceList parametersEnd(parameters);
  parametersEnd.insertContainer(qual_type_cons(NULL, typ_Pointer(
    pkind_PDataPointer(qual_type_cons(NULL, typ_Struct(qualified_name_cons(
      NULL, strdup("_frama_c_rtti_name_info_node")), tkind_TStandard()))))));
  parametersEnd.insertContainer(qual_type_cons(NULL, typ_Pointer(
    pkind_PDataPointer(qual_type_cons(NULL, typ_Struct(qualified_name_cons(
      NULL, strdup("_frama_c_rtti_name_info_content")), tkind_TStandard()))))));
  parametersEnd.insertContainer(qual_type_cons(NULL, typ_Int(IINT)));
  parametersEnd.insertContainer(qual_type_cons(NULL, typ_Int(IINT)));
  parametersEnd.insertContainer(qual_type_cons(NULL, typ_Int(IINT)));
  parametersEnd.insertContainer(qual_type_cons(NULL, typ_Int(IINT)));
  parametersEnd.insertContainer(qual_type_cons(NULL, typ_Pointer(
    pkind_PDataPointer(qual_type_cons(NULL, typ_Int(IINT))))));
  parametersEnd.insertContainer(qual_type_cons(NULL, typ_Pointer(
    pkind_PDataPointer(qual_type_cons(NULL, typ_Int(IINT))))));
  signature callSignature = signature_cons(qual_type_cons(NULL, typ_Int(IINT)),
    parameters, false /* variadic */);
  /* expression */ list callArguments = NULL;
  ForwardReferenceList callArgumentsEnd(callArguments);
  callArgumentsEnd.insertContainer(expression_cons(copy_loc(loc),
    exp_node_Variable(variable_FunctionParameter(strdup("target_info")))));
  callArgumentsEnd.insertContainer(expression_cons(copy_loc(loc),
    exp_node_FieldAccess(expression_cons(copy_loc(loc), exp_node_Dereference(
      expression_cons(copy_loc(loc), exp_node_FieldAccess(
        expression_cons(copy_loc(loc), exp_node_Dereference(
          expression_cons(copy_loc(loc), exp_node_Variable(variable_Local(
            qualified_name_cons(NULL, strdup("cursor"))))))),
        strdup("value"))))), strdup("base_classes"))));
  callArgumentsEnd.insertContainer(expression_cons(copy_loc(loc),
    exp_node_FieldAccess(expression_cons(copy_loc(loc), exp_node_Dereference(
      expression_cons(copy_loc(loc), exp_node_FieldAccess(
        expression_cons(copy_loc(loc), exp_node_Dereference(
          expression_cons(copy_loc(loc), exp_node_Variable(variable_Local(
            qualified_name_cons(NULL, strdup("cursor"))))))),
        strdup("value"))))), strdup("number_of_base_classes"))));
  callArgumentsEnd.insertContainer(expression_cons(copy_loc(loc),
    exp_node_Binary_operator(BOMINUS, AKRVALUE,
      expression_cons(copy_loc(loc), exp_node_Variable(
        variable_FunctionParameter(strdup("found_shift_object")))),
      expression_cons(copy_loc(loc), exp_node_FieldAccess(expression_cons(
        copy_loc(loc), exp_node_Dereference(expression_cons(copy_loc(loc),
          exp_node_Variable(variable_Local(qualified_name_cons(NULL,
            strdup("cursor"))))))), strdup("shift_object"))))));
  callArgumentsEnd.insertContainer(expression_cons(copy_loc(loc),
    exp_node_Binary_operator(BOMINUS, AKRVALUE,
      expression_cons(copy_loc(loc), exp_node_Variable(
        variable_FunctionParameter(strdup("found_shift_vmt")))),
      expression_cons(copy_loc(loc), exp_node_FieldAccess(expression_cons(
        copy_loc(loc), exp_node_Dereference(expression_cons(copy_loc(loc),
          exp_node_Variable(variable_Local(qualified_name_cons(NULL,
            strdup("cursor"))))))), strdup("shift_vmt"))))));
  callArgumentsEnd.insertContainer(
    expression_cons(
      copy_loc(loc),
      exp_node_Conditional(
        expression_cons(
          copy_loc(loc),
          exp_node_Binary_operator(
            BOLESS, AKRVALUE,
            expression_cons(
              copy_loc(loc),
              exp_node_Variable(
                variable_Local(
                  qualified_name_cons(NULL, strdup("base_index"))))),
            expression_cons(
              copy_loc(loc),
              exp_node_Binary_operator(
                BOMINUS, AKRVALUE,
                expression_cons(
                  copy_loc(loc),
                  exp_node_Variable(
                    variable_FunctionParameter(strdup("number_of_bases")))),
                makeIntLiteral(loc,IINT,1))))),
        expression_cons(
          copy_loc(loc),
          exp_node_FieldAccess(
            expression_cons(
              copy_loc(loc),
              exp_node_Dereference(
                expression_cons(
                  copy_loc(loc),
                  exp_node_Binary_operator(
                    BOPLUS, AKRVALUE,
                    expression_cons(
                      copy_loc(loc),
                      exp_node_Variable(
                        variable_Local(
                          qualified_name_cons(NULL, strdup("cursor"))))),
                    makeIntLiteral(loc,IINT,1))))),
            strdup("shift_vmt"))),
        expression_cons(
          copy_loc(loc),
          exp_node_Variable(
            variable_FunctionParameter(
              strdup("last_shift_vmt")))))));
  callArgumentsEnd.insertContainer(expression_cons(copy_loc(loc),
    exp_node_Address(expression_cons(copy_loc(loc),
      exp_node_Variable(variable_Local(qualified_name_cons(NULL,
        strdup("local_shift_object"))))))));
  callArgumentsEnd.insertContainer(expression_cons(copy_loc(loc),
    exp_node_Address(expression_cons(copy_loc(loc),
      exp_node_Variable(variable_Local(qualified_name_cons(NULL,
        strdup("local_distance"))))))));

  statementsEnd.insertContainer(statement_VarDecl(copy_loc(loc),
    strdup("local_result"), qual_type_cons(NULL, typ_Int(IINT)),
    opt_some_container(init_expr_Single_init(expression_cons(copy_loc(loc),
      exp_node_Static_call(
        qualified_name_cons(NULL, strdup("_frama_c_find_dynamic_cast_aux")),
        callSignature, funkind_FKFunction(),
        callArguments, tkind_TStandard(), false /* extern_c_call */))))));

  //       if (local_result && (local_distance >= 0)) {
  //         ...
  //       };
  statement* thenStatement = NULL;
  statement thenThenBlock = statement_Block(copy_loc(loc), NULL);
  statement condition =
    statement_Condition(
      copy_loc(loc),
      cond_statement_CondExpression(
        expression_cons(
          copy_loc(loc),
          exp_node_Binary_operator(
            BOLOGICALAND, AKRVALUE,
            expression_cons(
              copy_loc(loc),
              exp_node_Binary_operator(
                BODIFFERENT, AKRVALUE,
                expression_cons(
                  copy_loc(loc),
                  exp_node_Variable(
                    variable_Local(
                      qualified_name_cons(NULL, strdup("local_result"))))),
                makeIntLiteral(loc,IINT,0))),
            expression_cons(
              copy_loc(loc),
              exp_node_Binary_operator(
                BOGREATEROREQUAL, AKRVALUE,
                expression_cons(
                  copy_loc(loc),
                  exp_node_Variable(
                    variable_Local(
                      qualified_name_cons(NULL, strdup("local_distance"))))),
                makeIntLiteral(loc,IINT,0)))))),
      thenThenBlock,
      statement_Nop(copy_loc(loc)));
  statementsEnd.insertContainer(condition);
  thenStatement = &condition->cons_statement.Condition.then_instruction;

  //         if (*distance < 0 || *distance >= local_distance) {
  //           ...
  //         };
  /* statement */ list* thenThenBody = NULL;
  thenThenBody = &thenThenBlock->cons_statement.Block.instructions;
  *thenStatement =
    statement_Condition(
      copy_loc(loc),
      cond_statement_CondExpression(
        expression_cons(
          copy_loc(loc),
          exp_node_Binary_operator(
            BOLOGICALOR, AKRVALUE,
            expression_cons(
              copy_loc(loc),
              exp_node_Binary_operator(
                BOLESS, AKRVALUE,
                expression_cons(
                  copy_loc(loc),
                  exp_node_Dereference(
                    expression_cons(
                      copy_loc(loc),
                      exp_node_Variable(
                        variable_FunctionParameter(strdup("distance")))))),
                makeIntLiteral(loc,IINT,0))),
            expression_cons(
              copy_loc(loc),
              exp_node_Binary_operator(
                BOGREATEROREQUAL, AKRVALUE,
                expression_cons(
                  copy_loc(loc),
                  exp_node_Dereference(
                    expression_cons(
                      copy_loc(loc),
                      exp_node_Variable(
                        variable_FunctionParameter(strdup("distance")))))),
                expression_cons(
                  copy_loc(loc),
                  exp_node_Variable(
                    variable_Local(
                      qualified_name_cons(
                        NULL, strdup("local_distance")))))))))),
      thenThenBlock, statement_Nop(copy_loc(loc)));
  ForwardReferenceList thenThenBodyEnd(*thenThenBody);
  //           result = local_result;
  thenThenBodyEnd.insertContainer(statement_Expression(copy_loc(loc),
    expression_cons(copy_loc(loc), exp_node_Assign(
      expression_cons(copy_loc(loc), exp_node_Variable(variable_Local(
        qualified_name_cons(NULL, strdup("result"))))),
      expression_cons(copy_loc(loc), exp_node_Variable(variable_Local(
        qualified_name_cons(NULL, strdup("local_result")))))))));
  //           *shift_object = local_shift_object - cursor->shift_object;
  thenThenBodyEnd.insertContainer(statement_Expression(copy_loc(loc),
    expression_cons(copy_loc(loc), exp_node_Assign(
      expression_cons(copy_loc(loc), exp_node_Dereference(expression_cons(
        copy_loc(loc), exp_node_Variable(variable_FunctionParameter(
          strdup("shift_object")))))),
      expression_cons(copy_loc(loc), exp_node_Binary_operator(BOMINUS, AKRVALUE,
        expression_cons(copy_loc(loc), exp_node_Variable(variable_Local(
          qualified_name_cons(NULL, strdup("local_shift_object"))))),
        expression_cons(copy_loc(loc), exp_node_FieldAccess(expression_cons(
          copy_loc(loc), exp_node_Dereference(expression_cons(copy_loc(loc),
            exp_node_Variable(variable_Local(qualified_name_cons(NULL,
              strdup("cursor"))))))), strdup("shift_object")))))))));
  //           *distance = local_distance;
  thenThenBodyEnd.insertContainer(statement_Expression(copy_loc(loc),
    expression_cons(copy_loc(loc), exp_node_Assign(
      expression_cons(copy_loc(loc), exp_node_Dereference(expression_cons(
        copy_loc(loc), exp_node_Variable(variable_FunctionParameter(
          strdup("distance")))))),
      expression_cons(copy_loc(loc), exp_node_Variable(variable_Local(
        qualified_name_cons(NULL, strdup("local_distance")))))))));

  //       is_over = 1;
  statementsEnd.insertContainer(
    statement_Expression(
      copy_loc(loc),
      expression_cons(
        copy_loc(loc),
        exp_node_Assign(
          expression_cons(
            copy_loc(loc),
            exp_node_Variable(
              variable_Local(qualified_name_cons(NULL, strdup("is_over"))))),
          makeIntLiteral(loc,IINT,1)))));
}

void
RTTITable::insertRTTIAlgorithmsAuxWhileElseElseThenBodyPrelude(
    /* statement */ list* statements, location loc) {
  ForwardReferenceList statementsEnd(*statements);
//       int local_distance = 0;
  statementsEnd.insertContainer(
    statement_VarDecl(
      copy_loc(loc),
      strdup("local_distance"),
      qual_type_cons(NULL, typ_Int(IINT)),
      opt_some_container(init_expr_Single_init(makeIntLiteral(loc,IINT,0)))));
//       int local_shift_object = 0;
  statementsEnd.insertContainer(
    statement_VarDecl(
      copy_loc(loc),
      strdup("local_shift_object"),
      qual_type_cons(NULL, typ_Int(IINT)),
      opt_some_container(init_expr_Single_init(makeIntLiteral(loc,IINT,0)))));
//       int local_result = _frama_c_find_dynamic_cast_aux(target_info,
//         cursor->value->base_classes,
//         cursor->value->number_of_base_classes,
//         found_shift_object - cursor->shift_object,
//         found_shift_vmt - cursor->shift_vmt,
//         (base_index < number_of_bases-1) ? (cursor+1)->shift_vmt
//                                          : last_shift_vmt,
//         &local_shift_object, &local_distance);
  /* qual_type */ list parameters = NULL;
  ForwardReferenceList parametersEnd(parameters);
  parametersEnd.insertContainer(qual_type_cons(NULL, typ_Pointer(
    pkind_PDataPointer(qual_type_cons(NULL, typ_Struct(qualified_name_cons(
      NULL, strdup("_frama_c_rtti_name_info_node")), tkind_TStandard()))))));
  parametersEnd.insertContainer(qual_type_cons(NULL, typ_Pointer(
    pkind_PDataPointer(qual_type_cons(NULL, typ_Struct(qualified_name_cons(
      NULL, strdup("_frama_c_rtti_name_info_content")), tkind_TStandard()))))));
  parametersEnd.insertContainer(qual_type_cons(NULL, typ_Int(IINT)));
  parametersEnd.insertContainer(qual_type_cons(NULL, typ_Int(IINT)));
  parametersEnd.insertContainer(qual_type_cons(NULL, typ_Int(IINT)));
  parametersEnd.insertContainer(qual_type_cons(NULL, typ_Int(IINT)));
  parametersEnd.insertContainer(qual_type_cons(NULL, typ_Pointer(
    pkind_PDataPointer(qual_type_cons(NULL, typ_Int(IINT))))));
  parametersEnd.insertContainer(qual_type_cons(NULL, typ_Pointer(
    pkind_PDataPointer(qual_type_cons(NULL, typ_Int(IINT))))));
  signature callSignature = signature_cons(qual_type_cons(NULL, typ_Int(IINT)),
    parameters, false /* variadic */);
  /* expression */ list callArguments = NULL;
  ForwardReferenceList callArgumentsEnd(callArguments);
  callArgumentsEnd.insertContainer(expression_cons(copy_loc(loc),
    exp_node_Variable(variable_FunctionParameter(strdup("target_info")))));
  callArgumentsEnd.insertContainer(expression_cons(copy_loc(loc),
    exp_node_FieldAccess(expression_cons(copy_loc(loc), exp_node_Dereference(
      expression_cons(copy_loc(loc), exp_node_FieldAccess(
        expression_cons(copy_loc(loc), exp_node_Dereference(
          expression_cons(copy_loc(loc), exp_node_Variable(variable_Local(
            qualified_name_cons(NULL, strdup("cursor"))))))),
        strdup("value"))))), strdup("base_classes"))));
  callArgumentsEnd.insertContainer(expression_cons(copy_loc(loc),
    exp_node_FieldAccess(expression_cons(copy_loc(loc), exp_node_Dereference(
      expression_cons(copy_loc(loc), exp_node_FieldAccess(
        expression_cons(copy_loc(loc), exp_node_Dereference(
          expression_cons(copy_loc(loc), exp_node_Variable(variable_Local(
            qualified_name_cons(NULL, strdup("cursor"))))))),
        strdup("value"))))), strdup("number_of_base_classes"))));
  callArgumentsEnd.insertContainer(expression_cons(copy_loc(loc),
    exp_node_Binary_operator(BOMINUS, AKRVALUE,
      expression_cons(copy_loc(loc), exp_node_Variable(
        variable_FunctionParameter(strdup("found_shift_object")))),
      expression_cons(copy_loc(loc), exp_node_FieldAccess(expression_cons(
        copy_loc(loc), exp_node_Dereference(expression_cons(copy_loc(loc),
          exp_node_Variable(variable_Local(qualified_name_cons(NULL,
            strdup("cursor"))))))), strdup("shift_object"))))));
  callArgumentsEnd.insertContainer(expression_cons(copy_loc(loc),
    exp_node_Binary_operator(BOMINUS, AKRVALUE,
      expression_cons(copy_loc(loc), exp_node_Variable(
        variable_FunctionParameter(strdup("found_shift_vmt")))),
      expression_cons(copy_loc(loc), exp_node_FieldAccess(expression_cons(
        copy_loc(loc), exp_node_Dereference(expression_cons(copy_loc(loc),
          exp_node_Variable(variable_Local(qualified_name_cons(NULL,
            strdup("cursor"))))))), strdup("shift_vmt"))))));
  callArgumentsEnd.insertContainer(
    expression_cons(
      copy_loc(loc),
      exp_node_Conditional(
        expression_cons(
          copy_loc(loc),
          exp_node_Binary_operator(
            BOLESS, AKRVALUE,
            expression_cons(
              copy_loc(loc),
              exp_node_Variable(
                variable_Local(
                  qualified_name_cons(NULL, strdup("base_index"))))),
            expression_cons(
              copy_loc(loc),
              exp_node_Binary_operator(
                BOPLUS, AKRVALUE,
                expression_cons(
                  copy_loc(loc),
                  exp_node_Variable(
                    variable_FunctionParameter(strdup("number_of_bases")))),
                makeIntLiteral(loc,IINT,1))))),
        expression_cons(
          copy_loc(loc),
          exp_node_FieldAccess(
            expression_cons(
              copy_loc(loc),
              exp_node_Dereference(
                expression_cons(
                  copy_loc(loc),
                  exp_node_Binary_operator(
                    BOPLUS, AKRVALUE,
                    expression_cons(
                      copy_loc(loc),
                      exp_node_Variable(
                        variable_Local(
                          qualified_name_cons(NULL, strdup("cursor"))))),
                    makeIntLiteral(loc,IINT,1))))),
            strdup("shift_vmt"))),
        expression_cons(
          copy_loc(loc),
          exp_node_Variable(
            variable_FunctionParameter(strdup("last_shift_vmt")))))));
  callArgumentsEnd.insertContainer(expression_cons(copy_loc(loc),
    exp_node_Address(expression_cons(copy_loc(loc), exp_node_Variable(
      variable_Local(qualified_name_cons(NULL,
        strdup("local_shift_object"))))))));
  callArgumentsEnd.insertContainer(expression_cons(copy_loc(loc),
    exp_node_Address(expression_cons(copy_loc(loc), exp_node_Variable(
      variable_Local(qualified_name_cons(NULL, strdup("local_distance"))))))));

  statementsEnd.insertContainer(statement_VarDecl(copy_loc(loc),
    strdup("local_result"), qual_type_cons(NULL, typ_Int(IINT)),
    opt_some_container(init_expr_Single_init(expression_cons(copy_loc(loc),
      exp_node_Static_call(
        qualified_name_cons(NULL, strdup("_frama_c_find_dynamic_cast_aux")),
        callSignature, funkind_FKFunction(),
        callArguments, tkind_TStandard(), false /* extern_c_call */))))));

//       if (local_result && (local_distance >= 0)) {
//         ...
//       };
  statement* thenStatement = NULL;
  statement thenThenBlock = statement_Block(copy_loc(loc), NULL);
  statement condition =
    statement_Condition(
      copy_loc(loc),
      cond_statement_CondExpression(
        expression_cons(
          copy_loc(loc),
          exp_node_Binary_operator(
            BOLOGICALAND, AKRVALUE,
            expression_cons(
              copy_loc(loc),
              exp_node_Binary_operator(
                BODIFFERENT, AKRVALUE,
                expression_cons(
                  copy_loc(loc),
                  exp_node_Variable(
                    variable_Local(
                      qualified_name_cons(NULL, strdup("local_result"))))),
                makeIntLiteral(loc,IINT,0))),
            expression_cons(
              copy_loc(loc),
              exp_node_Binary_operator(
                BOGREATEROREQUAL, AKRVALUE,
                expression_cons(
                  copy_loc(loc),
                  exp_node_Variable(
                    variable_Local(
                      qualified_name_cons(NULL, strdup("local_distance"))))),
                makeIntLiteral(loc,IINT,0)))))),
      thenThenBlock, statement_Nop(copy_loc(loc)));
  statementsEnd.insertContainer(condition);
  thenStatement = &condition->cons_statement.Condition.then_instruction;

//         if (*distance < 0 || *distance
//               > (!is_over ? local_distance : (local_distance+1))) { ... };
  /* statemement */ list* thenThenBody = &thenThenBlock->cons_statement.Block
    .instructions;
  *thenStatement =
    statement_Condition(
      copy_loc(loc),
      cond_statement_CondExpression(
        expression_cons(
          copy_loc(loc),
          exp_node_Binary_operator(
            BOLOGICALOR, AKRVALUE,
            expression_cons(
              copy_loc(loc),
              exp_node_Binary_operator(
                BOLESS, AKRVALUE,
                expression_cons(
                  copy_loc(loc),
                  exp_node_Dereference(
                    expression_cons(
                      copy_loc(loc),
                      exp_node_Variable(
                        variable_FunctionParameter(strdup("distance")))))),
                makeIntLiteral(loc,IINT,0))),
            expression_cons(
              copy_loc(loc),
              exp_node_Binary_operator(
                BOGREATER, AKRVALUE,
                expression_cons(
                  copy_loc(loc),
                  exp_node_Dereference(
                    expression_cons(
                      copy_loc(loc),
                      exp_node_Variable(
                        variable_FunctionParameter(strdup("distance")))))),
                expression_cons(
                  copy_loc(loc),
                  exp_node_Conditional(
                    expression_cons(
                      copy_loc(loc),
                      exp_node_Binary_operator(
                        BOEQUAL, AKRVALUE,
                        expression_cons(
                          copy_loc(loc),
                          exp_node_Variable(
                            variable_Local(
                              qualified_name_cons(NULL, strdup("is_over"))))),
                        makeIntLiteral(loc,IINT,0))),
                    expression_cons(
                      copy_loc(loc),
                      exp_node_Variable(
                        variable_Local(
                          qualified_name_cons(
                            NULL, strdup("local_distance"))))),
                    expression_cons(
                      copy_loc(loc),
                      exp_node_Binary_operator(
                        BOPLUS, AKRVALUE,
                        expression_cons(
                          copy_loc(loc),
                          exp_node_Variable(
                            variable_Local(
                              qualified_name_cons(
                                NULL, strdup("local_distance"))))),
                        makeIntLiteral(loc,IINT,1)))))))))),
      thenThenBlock, statement_Nop(copy_loc(loc)));
  ForwardReferenceList thenThenBodyEnd(*thenThenBody);
//           result = local_result;
  thenThenBodyEnd.insertContainer(statement_Expression(copy_loc(loc),
    expression_cons(copy_loc(loc), exp_node_Assign(
      expression_cons(copy_loc(loc), exp_node_Variable(variable_Local(
        qualified_name_cons(NULL, strdup("result"))))),
      expression_cons(copy_loc(loc), exp_node_Variable(variable_Local(
        qualified_name_cons(NULL, strdup("local_result")))))))));
//           *shift_object = local_shift_object - cursor->shift_object;
  thenThenBodyEnd.insertContainer(statement_Expression(copy_loc(loc),
    expression_cons(copy_loc(loc), exp_node_Assign(
      expression_cons(copy_loc(loc), exp_node_Dereference(expression_cons(
        copy_loc(loc), exp_node_Variable(variable_FunctionParameter(
          strdup("shift_object")))))),
      expression_cons(copy_loc(loc), exp_node_Binary_operator(BOMINUS, AKRVALUE,
        expression_cons(copy_loc(loc), exp_node_Variable(variable_Local(
          qualified_name_cons(NULL, strdup("local_shift_object"))))),
        expression_cons(copy_loc(loc), exp_node_FieldAccess(expression_cons(
          copy_loc(loc), exp_node_Dereference(expression_cons(copy_loc(loc),
            exp_node_Variable(variable_Local(qualified_name_cons(NULL,
              strdup("cursor"))))))), strdup("shift_object")))))))));
//           *distance = local_distance+1;
  thenThenBodyEnd.insertContainer(
    statement_Expression(
      copy_loc(loc),
      expression_cons(
        copy_loc(loc),
        exp_node_Assign(
          expression_cons(
            copy_loc(loc),
            exp_node_Dereference(
              expression_cons(
                copy_loc(loc),
                exp_node_Variable(
                  variable_FunctionParameter(strdup("distance")))))),
          expression_cons(
            copy_loc(loc),
            exp_node_Binary_operator(
              BOPLUS, AKRVALUE,
              expression_cons(
                copy_loc(loc),
                exp_node_Variable(
                  variable_Local(
                    qualified_name_cons(NULL, strdup("local_distance"))))),
              makeIntLiteral(loc,IINT,1)))))));
}

// int _frama_c_find_dynamic_cast_aux(
//   struct _frama_c_rtti_name_info_node* target_info,
//   struct _frama_c_rtti_name_info_content* concrete_base,
//   int number_of_bases, int found_shift_object, int found_shift_vmt,
//   int last_shift_vmt, int* shift_object, int* distance)
// { int result = 0;
//   struct _frama_c_rtti_name_info_content* cursor = concrete_base;
//   int is_over = 0;
//   int base_index = 0;
//   while (base_index < number_of_bases) {
//     if (cursor->value == target_info) {
//       if (*distance < 0 || *distance >= 1) {
//           /* case 0 and 1 are not possible */
//         if (found_shift_vmt == cursor->shift_vmt)
//           *distance = 0; /* impossible case */
//         else
//           *distance = 1;
//         *shift_object = found_shift_object - cursor->shift_object;
//         result = 1;
//       }
//     }
//     else if (cursor->shift_vmt <= found_shift_vmt && (
//       (base_index < number_of_bases-1)
//         ? ((cursor+1)->shift_vmt > found_shift_vmt)
//         : ((last_shift_vmt == -1) || (found_shift_vmt < last_shift_vmt))))
//     { int local_distance = 0;
//       int local_shift_object = 0;
//       int local_result = _frama_c_find_dynamic_cast_aux(target_info,
//         cursor->value->base_classes,
//         cursor->value->number_of_base_classes,
//         found_shift_object - cursor->shift_object,
//         found_shift_vmt - cursor->shift_vmt,
//         (base_index < number_of_bases-1) ? (cursor+1)->shift_vmt
//                                          : last_shift_vmt,
//         &local_shift_object, &local_distance);
//       if (local_result && (local_distance >= 0)) {
//         if (*distance < 0 || *distance >= local_distance) {
//           result = local_result;
//           *shift_object = local_shift_object - cursor->shift_object;
//           *distance = local_distance;
//         };
//       };
//       is_over = 1;
//     }
//     else if (*distance < 0 || *distance > 1) {
//       int local_distance = 0;
//       int local_shift_object = 0;
//       int local_result = _frama_c_find_dynamic_cast_aux(target_info,
//         cursor->value->base_classes,
//         cursor->value->number_of_base_classes,
//         found_shift_object - cursor->shift_object,
//         found_shift_vmt - cursor->shift_vmt,
//         (base_index < number_of_bases-1) ? (cursor+1)->shift_vmt
//                                          : last_shift_vmt,
//         &local_shift_object, &local_distance);
//       if (local_result && (local_distance >= 0)) {
//         if (*distance < 0 || *distance
//               > (!is_over ? local_distance : (local_distance+1))) {
//           result = local_result;
//           *shift_object = local_shift_object - cursor->shift_object;
//           *distance = local_distance+1;
//         };
//       };
//     };
//     cursor = cursor+1;
//     base_index = base_index+1;
//   }; /* end of while */
//   return result;
// }

/* statement */ list*
RTTITable::insertRTTIAlgorithmsAuxPrelude(ForwardReferenceList& globals,
    location loc) {
  /* statement */ list* functionBody = insertRTTIAlgorithmsAuxDeclPrelude(
      globals, loc);
  /* statement */ list* whileBody = insertRTTIAlgorithmsAuxWhilePrelude(
      functionBody, loc);
  /* statement */ list* whileThen = NULL;
  /* statement */ list* whileElseThen = NULL;
  /* statement */ list* whileElseElseThen = NULL;
  insertRTTIAlgorithmsAuxWhileBodyPrelude(whileBody, loc, whileThen,
      whileElseThen, whileElseElseThen);
  insertRTTIAlgorithmsAuxWhileThenBodyPrelude(whileThen, loc);
  insertRTTIAlgorithmsAuxWhileElseThenBodyPrelude(whileElseThen, loc);
  insertRTTIAlgorithmsAuxWhileElseElseThenBodyPrelude(whileElseElseThen, loc);
  return functionBody;
}

/* statement */ list*
RTTITable::insertRTTIAlgorithmsDeclPrelude(ForwardReferenceList& globals,
    location loc) {
// int _frama_c_find_dynamic_cast(
//   struct _frama_c_rtti_name_info_node* declared_info,
//   struct _frama_c_vmt* declared_vmt, 
//   struct _frama_c_rtti_name_info_node* target_info,
//   int* shift_object) { ... }
  /* arg_decl */ list arguments = NULL;
  ForwardReferenceList argumentsEnd(arguments);
  argumentsEnd.insertContainer(arg_decl_cons(
    qual_type_cons(NULL, typ_Pointer(pkind_PDataPointer(qual_type_cons(NULL,
      typ_Struct(qualified_name_cons(NULL,
        strdup("_frama_c_rtti_name_info_node")), tkind_TStandard()))))),
    strdup("declared_info"), copy_loc(loc)));
  argumentsEnd.insertContainer(arg_decl_cons(
    qual_type_cons(NULL, typ_Pointer(pkind_PDataPointer(qual_type_cons(NULL,
      typ_Struct(qualified_name_cons(NULL, strdup("_frama_c_vmt")),
        tkind_TStandard()))))), strdup("declared_vmt"), copy_loc(loc)));
  argumentsEnd.insertContainer(arg_decl_cons(
    qual_type_cons(NULL, typ_Pointer(pkind_PDataPointer(qual_type_cons(NULL,
      typ_Struct(qualified_name_cons(NULL,
        strdup("_frama_c_rtti_name_info_node")), tkind_TStandard()))))),
    strdup("target_info"), copy_loc(loc)));
  argumentsEnd.insertContainer(arg_decl_cons(qual_type_cons(NULL,
      typ_Pointer(pkind_PDataPointer(qual_type_cons(NULL, typ_Int(IINT))))),
    strdup("shift_object"), copy_loc(loc)));

  /* statement list */ option result = opt_some_container(NULL);
  globals.insertContainer(
    translation_unit_decl_Function(
      decl_or_impl_name_Implementation(
        qualified_name_cons(NULL, strdup("_frama_c_find_dynamic_cast"))),
      funkind_FKFunction(), copy_loc(loc),
      qual_type_cons(NULL, typ_Int(IINT)), arguments, result,
      false /* is_extern_c */, false /* is_ghost */,
      false /* is_variadic */, tkind_TStandard(),
      false /* has_further_definition */,
      opt_none() /* throws */,
      opt_none() /* fun_spec */));
  return (/* statement */ list*) &result->content.container;
}

/* statement */ list*
RTTITable::insertRTTIAlgorithmsFirstPartPrelude(/* statement */ list*
    statements, location loc) {
  ForwardReferenceList statementsEnd(*statements);
//   struct _frama_c_rtti_name_info_node*
//     concrete_info = declared_vmt->rtti_info;
  statementsEnd.insertContainer(statement_VarDecl(copy_loc(loc),
    strdup("concrete_info"), qual_type_cons(NULL, typ_Pointer(
      pkind_PDataPointer(qual_type_cons(NULL, typ_Struct(qualified_name_cons(
        NULL, strdup("_frama_c_rtti_name_info_node")), tkind_TStandard()))))),
    opt_some_container(init_expr_Single_init(expression_cons(copy_loc(loc),
      exp_node_FieldAccess(expression_cons(copy_loc(loc), exp_node_Dereference(
        expression_cons(copy_loc(loc), exp_node_Variable(
          variable_FunctionParameter(strdup("declared_vmt")))))),
        strdup("rtti_info")))))));
//   int shift_vmt, elaborated_shift_vmt = 0, elaborated_shift_object = 0,
//       elaborated_shift_target;
  statementsEnd.insertContainer(statement_VarDecl(copy_loc(loc),
    strdup("shift_vmt"), qual_type_cons(NULL, typ_Int(IINT)), opt_none()));
  statementsEnd.insertContainer(
    statement_VarDecl(
      copy_loc(loc),
      strdup("elaborated_shift_vmt"),
      qual_type_cons(NULL, typ_Int(IINT)),
      opt_some_container(init_expr_Single_init(makeIntLiteral(loc,IINT,0)))));
  statementsEnd.insertContainer(
    statement_VarDecl(
      copy_loc(loc),
      strdup("elaborated_shift_object"),
      qual_type_cons(NULL, typ_Int(IINT)),
      opt_some_container(init_expr_Single_init(makeIntLiteral(loc,IINT,0)))));
  statementsEnd.insertContainer(
    statement_VarDecl(
      copy_loc(loc),
      strdup("elaborated_shift_target"),
      qual_type_cons(NULL, typ_Int(IINT)),
      opt_none()));
//   struct _frama_c_rtti_name_info_content* cursor;
//   int cursor_index = 0, number_of_bases;
//   int distance = -1;
  statementsEnd.insertContainer(statement_VarDecl(copy_loc(loc),
    strdup("cursor"), qual_type_cons(NULL, typ_Pointer(pkind_PDataPointer(
      qual_type_cons(NULL, typ_Struct(qualified_name_cons(NULL,
        strdup("_frama_c_rtti_name_info_content")), tkind_TStandard()))))),
        opt_none()));
  statementsEnd.insertContainer(
    statement_VarDecl(
      copy_loc(loc),
      strdup("cursor_index"),
      qual_type_cons(NULL, typ_Int(IINT)),
      opt_some_container(init_expr_Single_init(makeIntLiteral(loc,IINT,0)))));
  statementsEnd.insertContainer(
    statement_VarDecl(
      copy_loc(loc),
      strdup("number_of_bases"),
      qual_type_cons(NULL, typ_Int(IINT)),
      opt_none()));
  statementsEnd.insertContainer(
    statement_VarDecl(
      copy_loc(loc),
      strdup("distance"),
      qual_type_cons(NULL, typ_Int(IINT)),
      opt_some_container(
        init_expr_Single_init(
          expression_cons(
            copy_loc(loc),
            exp_node_Unary_operator(
              uokind_UOOpposite(),
              makeIntLiteral(loc,IINT,1)))))));

//   if (concrete_info->pvmt > declared_vmt
//       || declared_vmt > concrete_info->pvmt + declared_vmt->table_size)
//     return 0;
  statementsEnd.insertContainer(
    statement_Condition(
      copy_loc(loc),
      cond_statement_CondExpression(
        expression_cons(
          copy_loc(loc),
          exp_node_Binary_operator(
            BOLOGICALOR, AKRVALUE,
            expression_cons(
              copy_loc(loc),
              exp_node_Binary_operator(
                BOGREATER, AKRVALUE,
                expression_cons(
                  copy_loc(loc),
                  exp_node_FieldAccess(
                    expression_cons(
                      copy_loc(loc),
                      exp_node_Dereference(
                        expression_cons(
                          copy_loc(loc),
                          exp_node_Variable(
                            variable_Local(
                              qualified_name_cons(
                                NULL, strdup("concrete_info"))))))),
                    strdup("pvmt"))),
                expression_cons(
                  copy_loc(loc),
                  exp_node_Variable(
                    variable_FunctionParameter(strdup("declared_vmt")))))),
            expression_cons(
              copy_loc(loc),
              exp_node_Binary_operator(
                BOGREATER, AKRVALUE,
                expression_cons(
                  copy_loc(loc),
                  exp_node_Variable(
                    variable_FunctionParameter(strdup("declared_vmt")))),
                expression_cons(
                  copy_loc(loc),
                  exp_node_Binary_operator(
                    BOPLUS, AKRVALUE,
                    expression_cons(
                      copy_loc(loc),
                      exp_node_FieldAccess(
                        expression_cons(
                          copy_loc(loc),
                          exp_node_Dereference(
                            expression_cons(
                              copy_loc(loc),
                              exp_node_Variable(
                                variable_Local(
                                  qualified_name_cons(
                                    NULL, strdup("concrete_info"))))))),
                        strdup("pvmt"))),
                    expression_cons(
                      copy_loc(loc),
                      exp_node_FieldAccess(
                        expression_cons(
                          copy_loc(loc),
                          exp_node_Dereference(
                            expression_cons(
                              copy_loc(loc),
                              exp_node_Variable(
                                variable_FunctionParameter(
                                  strdup("declared_vmt")))))),
                        strdup("table_size")))))))))),
      statement_Return(
        copy_loc(loc),
        opt_some_container(makeIntLiteral(loc,IINT,0))),
      statement_Nop(copy_loc(loc))));
//   shift_vmt = declared_vmt - concrete_info->pvmt;
//     // 0 <= shift_vmt <= table_size
  statementsEnd.insertContainer(statement_Expression(copy_loc(loc),
    expression_cons(copy_loc(loc), exp_node_Assign(
      expression_cons(copy_loc(loc), exp_node_Variable(
        variable_Local(qualified_name_cons(NULL, strdup("shift_vmt"))))),
      expression_cons(copy_loc(loc), exp_node_Binary_operator(BOMINUS, AKRVALUE,
        expression_cons(copy_loc(loc), exp_node_Variable(
          variable_FunctionParameter(strdup("declared_vmt")))),
        expression_cons(copy_loc(loc), exp_node_FieldAccess(expression_cons(
          copy_loc(loc), exp_node_Dereference(expression_cons(copy_loc(loc),
            exp_node_Variable(variable_Local(qualified_name_cons(NULL,
              strdup("concrete_info"))))))), strdup("pvmt")))))))));
//   if (concrete_info == declared_info) {
//     *shift_object = 0;
//     return (target_info == declared_info);
//   };
  /* statement */ list ifThenBody = NULL;
  { ForwardReferenceList ifThenBodyEnd(ifThenBody);
    ifThenBodyEnd.insertContainer(
      statement_Expression(
        copy_loc(loc),
        expression_cons(
          copy_loc(loc),
          exp_node_Assign(
            expression_cons(
              copy_loc(loc),
              exp_node_Dereference(
                expression_cons(
                  copy_loc(loc),
                  exp_node_Variable(
                    variable_FunctionParameter(strdup("shift_object")))))),
            makeIntLiteral(loc,IINT,0)))));
    ifThenBodyEnd.insertContainer(statement_Return(copy_loc(loc),
      opt_some_container(expression_cons(copy_loc(loc),
        exp_node_Binary_operator(BOEQUAL, AKRVALUE,
          expression_cons(copy_loc(loc), exp_node_Variable(
            variable_FunctionParameter(strdup("target_info")))),
          expression_cons(copy_loc(loc), exp_node_Variable(
            variable_FunctionParameter(strdup("declared_info")))))))));
  };
  statementsEnd.insertContainer(statement_Condition(copy_loc(loc),
    cond_statement_CondExpression(expression_cons(copy_loc(loc),
      exp_node_Binary_operator(BOEQUAL, AKRVALUE,
        expression_cons(copy_loc(loc), exp_node_Variable(
          variable_Local(qualified_name_cons(NULL, strdup("concrete_info"))))),
        expression_cons(copy_loc(loc), exp_node_Variable(
          variable_FunctionParameter(strdup("declared_info"))))))),
    statement_Block(copy_loc(loc), ifThenBody),
    statement_Nop(copy_loc(loc))));
//   elaborated_shift_target = (target_info == concrete_info) ? 0 : -1;
  statementsEnd.insertContainer(
    statement_Expression(
      copy_loc(loc),
      expression_cons(
        copy_loc(loc),
        exp_node_Assign(
          expression_cons(
            copy_loc(loc),
            exp_node_Variable(
              variable_Local(
                qualified_name_cons(NULL, strdup("elaborated_shift_target"))))),
          expression_cons(
            copy_loc(loc),
            exp_node_Conditional(
              expression_cons(
                copy_loc(loc),
                exp_node_Binary_operator(
                  BOEQUAL, AKRVALUE,
                  expression_cons(
                    copy_loc(loc),
                    exp_node_Variable(
                      variable_FunctionParameter(strdup("target_info")))),
                  expression_cons(
                    copy_loc(loc),
                    exp_node_Variable(
                      variable_Local(
                        qualified_name_cons(NULL, strdup("concrete_info"))))))),
              makeIntLiteral(loc,IINT,0),
              expression_cons(
                copy_loc(loc),
                exp_node_Unary_operator(
                  uokind_UOOpposite(),
                  makeIntLiteral(loc,IINT,1)))))))));
//   cursor = concrete_info->base_classes;
  statementsEnd.insertContainer(statement_Expression(copy_loc(loc),
    expression_cons(copy_loc(loc), exp_node_Assign(
      expression_cons(copy_loc(loc), exp_node_Variable(variable_Local(
        qualified_name_cons(NULL, strdup("cursor"))))),
      expression_cons(copy_loc(loc), exp_node_FieldAccess(
        expression_cons(copy_loc(loc), exp_node_Dereference(
          expression_cons(copy_loc(loc), exp_node_Variable(variable_Local(
            qualified_name_cons(NULL, strdup("concrete_info"))))))),
          strdup("base_classes")))))));
//   number_of_bases = concrete_info->number_of_base_classes;
  statementsEnd.insertContainer(statement_Expression(copy_loc(loc),
    expression_cons(copy_loc(loc), exp_node_Assign(
      expression_cons(copy_loc(loc), exp_node_Variable(variable_Local(
        qualified_name_cons(NULL, strdup("number_of_bases"))))),
      expression_cons(copy_loc(loc), exp_node_FieldAccess(
        expression_cons(copy_loc(loc), exp_node_Dereference(
          expression_cons(copy_loc(loc), exp_node_Variable(variable_Local(
            qualified_name_cons(NULL, strdup("concrete_info"))))))),
          strdup("number_of_base_classes")))))));
  return statementsEnd.getBack() ? &statementsEnd.getBack()->next : NULL;
}

/* statement */ list*
RTTITable::insertRTTIAlgorithmsDoWhilePrelude(/* statement */ list*&
    statements, location loc) {
  ForwardReferenceList statementsEnd(*statements);
//   do { ...  } while (cursor_index < number_of_bases);
  statement doWhileBody = statement_Block(copy_loc(loc), NULL);
  statementsEnd.insertContainer(statement_DoWhile(copy_loc(loc),
    expression_cons(copy_loc(loc), exp_node_Binary_operator(BOLESS,
      AKRVALUE, expression_cons(copy_loc(loc), exp_node_Variable(variable_Local(
        qualified_name_cons(NULL, strdup("cursor_index"))))),
      expression_cons(copy_loc(loc), exp_node_Variable(variable_Local(
        qualified_name_cons(NULL, strdup("number_of_bases"))))))),
    doWhileBody, NULL));
  statements = statementsEnd.getBack() ? &statementsEnd.getBack()->next : NULL;
  return (/*statement */ list*) &doWhileBody->cons_statement.Block.instructions;
}

/* statement */ list*
RTTITable::insertRTTIAlgorithmsSecondWhilePrelude(/* statement */ list*&
    statements, location loc) {
//     while ((cursor_index < number_of_bases)
//         && (elaborated_shift_vmt+cursor->shift_vmt < shift_vmt))
//     { ... };
  ForwardReferenceList statementsEnd(*statements);
  statement whileBody = statement_Block(copy_loc(loc), NULL);
  statementsEnd.insertContainer(statement_While(copy_loc(loc),
    expression_cons(copy_loc(loc), exp_node_Binary_operator(BOLOGICALAND,
      AKRVALUE, expression_cons(copy_loc(loc), exp_node_Binary_operator(
        BOLESS, AKRVALUE, expression_cons(copy_loc(loc), exp_node_Variable(
          variable_Local(qualified_name_cons(NULL, strdup("cursor_index"))))),
        expression_cons(copy_loc(loc), exp_node_Variable(variable_Local(
          qualified_name_cons(NULL, strdup("number_of_bases"))))))),
      expression_cons(copy_loc(loc), exp_node_Binary_operator(BOLESS, AKRVALUE,
        expression_cons(copy_loc(loc), exp_node_Binary_operator(BOPLUS,
          AKRVALUE, expression_cons(copy_loc(loc), exp_node_Variable(
            variable_Local(qualified_name_cons(NULL,
              strdup("elaborated_shift_vmt"))))),
          expression_cons(copy_loc(loc), exp_node_FieldAccess(expression_cons(
            copy_loc(loc), exp_node_Dereference(expression_cons(copy_loc(loc),
              exp_node_Variable(variable_Local(qualified_name_cons(NULL,
                strdup("cursor"))))))), strdup("shift_vmt"))))),
        expression_cons(copy_loc(loc), exp_node_Variable(variable_Local(
          qualified_name_cons(NULL, strdup("shift_vmt"))))))))),
    whileBody, NULL /* annot */));
  statements = statementsEnd.getBack() ? &statementsEnd.getBack()->next : NULL;
  return (/* statement */ list*) &whileBody->cons_statement.Block.instructions;
}

void
RTTITable::insertRTTIAlgorithmsSecondWhileBodyPrelude(/* statement */ list*&
    statements, location loc) {
  ForwardReferenceList statementsEnd(*statements);
//       struct _frama_c_rtti_name_info_content* next_cursor
//         = (cursor_index < number_of_bases-1) ? (cursor+1)
//             : (struct _frama_c_rtti_name_info_content*) 0;
  statementsEnd.insertContainer(
    statement_VarDecl(
      copy_loc(loc),
      strdup("next_cursor"),
      qual_type_cons(
        NULL,
        typ_Pointer(
          pkind_PDataPointer(
            qual_type_cons(
              NULL,
              typ_Struct(
                qualified_name_cons(
                  NULL, strdup("_frama_c_rtti_name_info_content")),
                tkind_TStandard()))))),
      opt_some_container(
        init_expr_Single_init(
          expression_cons(
            copy_loc(loc),
            exp_node_Conditional(
              expression_cons(
                copy_loc(loc),
                exp_node_Binary_operator(
                  BOLESS, AKRVALUE,
                  expression_cons(
                    copy_loc(loc),
                    exp_node_Variable(
                      variable_Local(
                        qualified_name_cons(NULL, strdup("cursor_index"))))),
                  expression_cons(
                    copy_loc(loc),
                    exp_node_Binary_operator(
                      BOMINUS, AKRVALUE,
                      expression_cons(
                        copy_loc(loc),
                        exp_node_Variable(
                          variable_Local(
                            qualified_name_cons(
                              NULL, strdup("number_of_bases"))))),
                      makeIntLiteral(loc,IINT,1))))),
              expression_cons(
                copy_loc(loc),
                exp_node_Binary_operator(
                  BOPLUS, AKRVALUE,
                  expression_cons(
                    copy_loc(loc),
                    exp_node_Variable(
                      variable_Local(
                        qualified_name_cons(NULL, strdup("cursor"))))),
                  makeIntLiteral(loc,IINT,1))),
              makeNullPointer(
                loc,
                makeStructType(
                  qualified_name_cons(
                    NULL,strdup("_frama_c_rtti_name_info_content"))))))))));
//       if (next_cursor
//           && (elaborated_shift_vmt + next_cursor->shift_vmt <= shift_vmt)) {
//         cursor = next_cursor;
//         cursor_index = cursor_index + 1;
//       }
//       else
//         break;
  statement lastCondition =
    statement_Condition(
      copy_loc(loc),
      cond_statement_CondExpression(
        expression_cons(
          copy_loc(loc),
          exp_node_Binary_operator(
            BOLOGICALAND, AKRVALUE,
            expression_cons(
              copy_loc(loc),
              exp_node_Binary_operator(
                BODIFFERENT, AKRVALUE,
                expression_cons(
                  copy_loc(loc),
                  exp_node_Variable(
                    variable_Local(
                      qualified_name_cons(NULL, strdup("next_cursor"))))),
                makeNullPointer(
                  loc,
                  makeStructType(
                    qualified_name_cons(
                      NULL,strdup("_frama_c_rtti_name_info_content")))))),
            expression_cons(
              copy_loc(loc),
              exp_node_Binary_operator(
                BOLESSOREQUAL, AKRVALUE,
                expression_cons(
                  copy_loc(loc),
                  exp_node_Binary_operator(
                    BOPLUS, AKRVALUE,
                    expression_cons(
                      copy_loc(loc),
                      exp_node_Variable(
                        variable_Local(
                          qualified_name_cons(
                            NULL, strdup("elaborated_shift_vmt"))))),
                    expression_cons(
                      copy_loc(loc),
                      exp_node_FieldAccess(
                        expression_cons(
                          copy_loc(loc),
                          exp_node_Dereference(
                            expression_cons(
                              copy_loc(loc),
                              exp_node_Variable(
                                variable_Local(
                                  qualified_name_cons(
                                    NULL, strdup("next_cursor"))))))),
                        strdup("shift_vmt"))))),
                expression_cons(
                  copy_loc(loc),
                  exp_node_Variable(
                    variable_Local(
                      qualified_name_cons(NULL, strdup("shift_vmt")))))))))),
      statement_Block(copy_loc(loc), NULL), 
      statement_Break(copy_loc(loc)));

  ForwardReferenceList lastConditionThenBlock(lastCondition->cons_statement
    .Condition.then_instruction->cons_statement.Block.instructions);
  lastConditionThenBlock.insertContainer(statement_Expression(copy_loc(loc),
    expression_cons(copy_loc(loc), exp_node_Assign(
      expression_cons(copy_loc(loc), exp_node_Variable(
        variable_Local(qualified_name_cons(NULL, strdup("cursor"))))),
      expression_cons(copy_loc(loc), exp_node_Variable(variable_Local(
        qualified_name_cons(NULL, strdup("next_cursor")))))))));
  lastConditionThenBlock.insertContainer(
    statement_Expression(
      copy_loc(loc),
      expression_cons(
        copy_loc(loc),
        exp_node_Assign(
          expression_cons(
            copy_loc(loc),
            exp_node_Variable(
              variable_Local(
                qualified_name_cons(NULL, strdup("cursor_index"))))),
          expression_cons(
            copy_loc(loc),
            exp_node_Binary_operator(
              BOPLUS, AKRVALUE,
              expression_cons(
                copy_loc(loc),
                exp_node_Variable(
                  variable_Local(
                    qualified_name_cons(NULL, strdup("cursor_index"))))),
              makeIntLiteral(loc,IINT,1)))))));
  statementsEnd.insertContainer(lastCondition);
  statements = statementsEnd.getBack() ? &statementsEnd.getBack()->next : NULL;
}

/* statement */ list*
RTTITable::insertRTTIAlgorithmsSecondIfThenPrelude(/* statement */ list*&
    statements, location loc) {
  ForwardReferenceList statementsEnd(*statements);
//     if (cursor_index < number_of_bases) { ... };
  statement thenBlock = statement_Block(copy_loc(loc), NULL);
  statementsEnd.insertContainer(statement_Condition(copy_loc(loc),
    cond_statement_CondExpression(expression_cons(copy_loc(loc),
      exp_node_Binary_operator(BOLESS, AKRVALUE,
        expression_cons(copy_loc(loc), exp_node_Variable(variable_Local(
          qualified_name_cons(NULL, strdup("cursor_index"))))),
        expression_cons(copy_loc(loc), exp_node_Variable(variable_Local(
          qualified_name_cons(NULL, strdup("number_of_bases")))))))),
    thenBlock, statement_Nop(copy_loc(loc))));
  statements = statementsEnd.getBack() ? &statementsEnd.getBack()->next : NULL;
  return (/* statement */ list*) &thenBlock->cons_statement.Block.instructions;
}

void
RTTITable::insertRTTIAlgorithmsSecondIfThenBodyPrelude(/* statement */ list*&
    statements, location loc) {
  ForwardReferenceList statementsEnd(*statements);
//       elaborated_shift_vmt += cursor->shift_vmt;
  statementsEnd.insertContainer(statement_Expression(copy_loc(loc),
    expression_cons(copy_loc(loc), exp_node_Binary_operator(BOPLUS,
      AKASSIGN, expression_cons(copy_loc(loc), exp_node_Variable(
        variable_Local(qualified_name_cons(NULL,
          strdup("elaborated_shift_vmt"))))),
      expression_cons(copy_loc(loc), exp_node_FieldAccess(expression_cons(
        copy_loc(loc), exp_node_Dereference(expression_cons(copy_loc(loc),
          exp_node_Variable(variable_Local(qualified_name_cons(NULL,
            strdup("cursor"))))))), strdup("shift_vmt")))))));
//       elaborated_shift_object += cursor->shift_object;
  statementsEnd.insertContainer(statement_Expression(copy_loc(loc),
    expression_cons(copy_loc(loc), exp_node_Binary_operator(BOPLUS,
      AKASSIGN, expression_cons(copy_loc(loc), exp_node_Variable(
        variable_Local(qualified_name_cons(NULL,
          strdup("elaborated_shift_object"))))),
      expression_cons(copy_loc(loc), exp_node_FieldAccess(expression_cons(
        copy_loc(loc), exp_node_Dereference(expression_cons(copy_loc(loc),
          exp_node_Variable(variable_Local(qualified_name_cons(NULL,
            strdup("cursor"))))))), strdup("shift_object")))))));
//       if (cursor->value == target_info)
//         elaborated_shift_target = elaborated_shift_object;
  statementsEnd.insertContainer(
    statement_Condition(
      copy_loc(loc),
      cond_statement_CondExpression(
        expression_cons(
          copy_loc(loc),
          exp_node_Binary_operator(
            BOEQUAL, AKRVALUE,
            expression_cons(
              copy_loc(loc),
              exp_node_FieldAccess(
                expression_cons(
                  copy_loc(loc),
                  exp_node_Dereference(
                    expression_cons(
                      copy_loc(loc),
                      exp_node_Variable(
                        variable_Local(
                          qualified_name_cons(NULL, strdup("cursor"))))))),
                strdup("value"))),
            expression_cons(
              copy_loc(loc),
              exp_node_Variable(
                variable_FunctionParameter(strdup("target_info"))))))),
      statement_Expression(
        copy_loc(loc),
        expression_cons(
          copy_loc(loc),
          exp_node_Assign(
            expression_cons(
              copy_loc(loc),
              exp_node_Variable(
                variable_Local(
                  qualified_name_cons(
                    NULL, strdup("elaborated_shift_target"))))),
            expression_cons(
              copy_loc(loc),
              exp_node_Variable(
                variable_Local(
                  qualified_name_cons(
                    NULL, strdup("elaborated_shift_object")))))))),
      statement_Nop(copy_loc(loc))));
//       if (elaborated_shift_vmt == shift_vmt
//           && cursor->value == declared_info) {
//         if (elaborated_shift_target >= 0) {
//           *shift_object = elaborated_shift_target-elaborated_shift_object;
//           return 1;
//         };
//         break;
//       };
  /* statement */ list innerIfThenBody = NULL;
  ForwardReferenceList innerIfThenBodyEnd(innerIfThenBody);
  innerIfThenBodyEnd.insertContainer(statement_Expression(copy_loc(loc),
    expression_cons(copy_loc(loc), exp_node_Assign(
      expression_cons(copy_loc(loc), exp_node_Dereference(expression_cons(
        copy_loc(loc), exp_node_Variable(variable_FunctionParameter(
          strdup("shift_object")))))),
      expression_cons(copy_loc(loc), exp_node_Binary_operator(BOMINUS, AKRVALUE,
        expression_cons(copy_loc(loc), exp_node_Variable(variable_Local(
          qualified_name_cons(NULL, strdup("elaborated_shift_target"))))),
        expression_cons(copy_loc(loc), exp_node_Variable(variable_Local(
          qualified_name_cons(NULL, strdup("elaborated_shift_object")))))))))));
  innerIfThenBodyEnd.insertContainer(
    statement_Return(
      copy_loc(loc),
      opt_some_container(makeIntLiteral(loc,IINT,1))));

  /* statement */ list ifThenBody = NULL;
  ForwardReferenceList ifThenBodyEnd(ifThenBody);
  ifThenBodyEnd.insertContainer(
    statement_Condition(
      copy_loc(loc),
      cond_statement_CondExpression(
        expression_cons(
          copy_loc(loc),
          exp_node_Binary_operator(
            BOGREATEROREQUAL, AKRVALUE,
            expression_cons(
              copy_loc(loc),
              exp_node_Variable(
                variable_Local(
                  qualified_name_cons(
                    NULL, strdup("elaborated_shift_target"))))),
            makeIntLiteral(loc,IINT,0)))),
      statement_Block(copy_loc(loc), innerIfThenBody),
      statement_Nop(copy_loc(loc))));
  ifThenBodyEnd.insertContainer(statement_Break(copy_loc(loc)));

  statementsEnd.insertContainer(
    statement_Condition(
      copy_loc(loc),
      cond_statement_CondExpression(
        expression_cons(
          copy_loc(loc),
          exp_node_Binary_operator(
            BOLOGICALAND, AKRVALUE,
            expression_cons(
              copy_loc(loc),
              exp_node_Binary_operator(
                BOEQUAL,
                AKRVALUE,
                expression_cons(
                  copy_loc(loc),
                  exp_node_Variable(
                    variable_Local(
                      qualified_name_cons(
                        NULL, strdup("elaborated_shift_vmt"))))),
                expression_cons(
                  copy_loc(loc),
                  exp_node_Variable(
                    variable_Local(
                      qualified_name_cons(NULL, strdup("shift_vmt"))))))),
            expression_cons(
              copy_loc(loc),
              exp_node_Binary_operator(
                BOEQUAL, AKRVALUE,
                expression_cons(
                  copy_loc(loc),
                  exp_node_FieldAccess(
                    expression_cons(
                      copy_loc(loc),
                      exp_node_Dereference(
                        expression_cons(
                          copy_loc(loc),
                          exp_node_Variable(
                            variable_Local(
                              qualified_name_cons(NULL, strdup("cursor"))))))),
                    strdup("value"))),
                expression_cons(
                  copy_loc(loc),
                  exp_node_Variable(
                    variable_FunctionParameter(strdup("declared_info"))))))))),
      statement_Block(copy_loc(loc), ifThenBody),
      statement_Nop(copy_loc(loc))));

//       cursor = cursor->value->base_classes;
  statementsEnd.insertContainer(statement_Expression(copy_loc(loc),
    expression_cons(copy_loc(loc), exp_node_Assign(
      expression_cons(copy_loc(loc), exp_node_Variable(variable_Local(
        qualified_name_cons(NULL, strdup("cursor"))))),
      expression_cons(copy_loc(loc), exp_node_FieldAccess(
        expression_cons(copy_loc(loc), exp_node_Dereference(
          expression_cons(copy_loc(loc), exp_node_FieldAccess(
            expression_cons(copy_loc(loc), exp_node_Dereference(
              expression_cons(copy_loc(loc), exp_node_Variable(variable_Local(
                qualified_name_cons(NULL, strdup("cursor"))))))),
            strdup("value"))))),
        strdup("base_classes")))))));
//       number_of_bases = cursor->value->number_of_base_classes;
  statementsEnd.insertContainer(statement_Expression(copy_loc(loc),
    expression_cons(copy_loc(loc), exp_node_Assign(
      expression_cons(copy_loc(loc), exp_node_Variable(variable_Local(
        qualified_name_cons(NULL, strdup("number_of_bases"))))),
      expression_cons(copy_loc(loc), exp_node_FieldAccess(
        expression_cons(copy_loc(loc), exp_node_Dereference(
          expression_cons(copy_loc(loc), exp_node_FieldAccess(
            expression_cons(copy_loc(loc), exp_node_Dereference(
              expression_cons(copy_loc(loc), exp_node_Variable(variable_Local(
                qualified_name_cons(NULL, strdup("cursor"))))))),
            strdup("value"))))),
        strdup("number_of_base_classes")))))));
//       cursor_index = 0;
  statementsEnd.insertContainer(
    statement_Expression(
      copy_loc(loc),
      expression_cons(
        copy_loc(loc),
        exp_node_Assign(
          expression_cons(
            copy_loc(loc),
            exp_node_Variable(
              variable_Local(
                qualified_name_cons(NULL, strdup("cursor_index"))))),
          makeIntLiteral(loc,IINT,0)))));

  statements = statementsEnd.getBack() ? &statementsEnd.getBack()->next : NULL;
}

void
RTTITable::insertRTTIAlgorithmsLastPartPrelude(/* statement */ list*&
    statements, location loc) {
  ForwardReferenceList statementsEnd(*statements);
//   if (cursor_index >= number_of_bases)
//     return 0;
  statementsEnd.insertContainer(
    statement_Condition(
      copy_loc(loc),
      cond_statement_CondExpression(
        expression_cons(
          copy_loc(loc),
          exp_node_Binary_operator(
            BOGREATEROREQUAL, AKRVALUE,
            expression_cons(
              copy_loc(loc),
              exp_node_Variable(
                variable_Local(
                  qualified_name_cons(NULL, strdup("cursor_index"))))),
            expression_cons(
              copy_loc(loc),
              exp_node_Variable(
                variable_Local(
                  qualified_name_cons(NULL, strdup("number_of_bases")))))))),
      statement_Return(
        copy_loc(loc),
        opt_some_container(makeIntLiteral(loc,IINT,0))),
      statement_Nop(copy_loc(loc))));
//   // elaborated_shift_target == -1 && cursor->value == target_info
//   //   && elaborated_shift_vmt == shift_vmt
//   return _frama_c_find_dynamic_cast_aux(target_info,
//     concrete_info->base_classes,
//     concrete_info->number_of_base_classes,
//     elaborated_shift_object, shift_vmt, -1, shift_object, &distance);
  /* qual_type */ list parameters = NULL;
  ForwardReferenceList parametersEnd(parameters);
  parametersEnd.insertContainer(qual_type_cons(NULL, typ_Pointer(
    pkind_PDataPointer(qual_type_cons(NULL, typ_Struct(qualified_name_cons(
      NULL, strdup("_frama_c_rtti_name_info_node")), tkind_TStandard()))))));
  parametersEnd.insertContainer(qual_type_cons(NULL, typ_Pointer(
    pkind_PDataPointer(qual_type_cons(NULL, typ_Struct(qualified_name_cons(
      NULL, strdup("_frama_c_rtti_name_info_content")), tkind_TStandard()))))));
  parametersEnd.insertContainer(qual_type_cons(NULL, typ_Int(IINT)));
  parametersEnd.insertContainer(qual_type_cons(NULL, typ_Int(IINT)));
  parametersEnd.insertContainer(qual_type_cons(NULL, typ_Int(IINT)));
  parametersEnd.insertContainer(qual_type_cons(NULL, typ_Int(IINT)));
  parametersEnd.insertContainer(qual_type_cons(NULL, typ_Pointer(
    pkind_PDataPointer(qual_type_cons(NULL, typ_Int(IINT))))));
  parametersEnd.insertContainer(qual_type_cons(NULL, typ_Pointer(
    pkind_PDataPointer(qual_type_cons(NULL, typ_Int(IINT))))));

  /* expression */ list arguments = NULL;
  ForwardReferenceList argumentsEnd(arguments);
  argumentsEnd.insertContainer(expression_cons(copy_loc(loc), exp_node_Variable(
    variable_FunctionParameter(strdup("target_info")))));
  argumentsEnd.insertContainer(expression_cons(copy_loc(loc),
    exp_node_FieldAccess(expression_cons(copy_loc(loc), exp_node_Dereference(
      expression_cons(copy_loc(loc), exp_node_Variable(variable_Local(
        qualified_name_cons(NULL, strdup("concrete_info"))))))),
      strdup("base_classes"))));
  argumentsEnd.insertContainer(expression_cons(copy_loc(loc),
    exp_node_FieldAccess(expression_cons(copy_loc(loc), exp_node_Dereference(
      expression_cons(copy_loc(loc), exp_node_Variable(variable_Local(
        qualified_name_cons(NULL, strdup("concrete_info"))))))),
      strdup("number_of_base_classes"))));
  argumentsEnd.insertContainer(expression_cons(copy_loc(loc), exp_node_Variable(
    variable_Local(qualified_name_cons(NULL,
      strdup("elaborated_shift_object"))))));
  argumentsEnd.insertContainer(expression_cons(copy_loc(loc), exp_node_Variable(
    variable_Local(qualified_name_cons(NULL, strdup("shift_vmt"))))));
  argumentsEnd.insertContainer(
    expression_cons(
      copy_loc(loc),
      exp_node_Unary_operator(
        uokind_UOOpposite(),
        makeIntLiteral(loc,IINT,1))));
  argumentsEnd.insertContainer(expression_cons(copy_loc(loc), exp_node_Variable(
    variable_FunctionParameter(strdup("shift_object")))));
  argumentsEnd.insertContainer(expression_cons(copy_loc(loc), exp_node_Address(
    expression_cons(copy_loc(loc), exp_node_Variable(variable_Local(
      qualified_name_cons(NULL, strdup("distance"))))))));
  
  statementsEnd.insertContainer(
    statement_Return(
      copy_loc(loc),
      opt_some_container(
        expression_cons(
          copy_loc(loc),
          exp_node_Static_call(
            qualified_name_cons(NULL, strdup("_frama_c_find_dynamic_cast_aux")),
            signature_cons(
              qual_type_cons(NULL, typ_Int(IINT)), parameters, false),
            funkind_FKFunction(),
            arguments, tkind_TStandard(), false /* extern_c_call */)))));

  statements = statementsEnd.getBack() ? &statementsEnd.getBack()->next : NULL;
}

// int _frama_c_find_dynamic_cast(
//   struct _frama_c_rtti_name_info_node* declared_info,
//   struct _frama_c_vmt* declared_vmt, 
//   struct _frama_c_rtti_name_info_node* target_info,
//   int* shift_object)
// { struct _frama_c_rtti_name_info_node*
//     concrete_info = declared_vmt->rtti_info;
//   int shift_vmt, elaborated_shift_vmt = 0, elaborated_shift_object = 0,
//       elaborated_shift_target;
//   struct _frama_c_rtti_name_info_content* cursor;
//   int cursor_index = 0, number_of_bases;
//   int distance = -1;
//   if (concrete_info->pvmt > declared_vmt
//       || declared_vmt > concrete_info->pvmt + declared_vmt->table_size)
//     return 0;
//   shift_vmt = declared_vmt - concrete_info->pvmt;
//     // 0 <= shift_vmt <= table_size
//   if (concrete_info == declared_info) {
//     *shift_object = 0;
//     return (target_info == declared_info);
//   };
//   elaborated_shift_target = (target_info == concrete_info) ? 0 : -1;
//   cursor = concrete_info->base_classes;
//   number_of_bases = concrete_info->number_of_base_classes;
//   do {
//     while ((cursor_index < number_of_bases)
//         && (elaborated_shift_vmt+cursor->shift_vmt < shift_vmt))
//     { struct _frama_c_rtti_name_info_content* next_cursor
//         = (cursor_index < number_of_bases-1) ? (cursor+1)
//             : (struct _frama_c_rtti_name_info_content*) 0;
//       if (next_cursor
//           && (elaborated_shift_vmt + next_cursor->shift_vmt <= shift_vmt)) {
//         cursor = next_cursor;
//         cursor_index = cursor_index + 1;
//       }
//       else
//         break;
//     };
//     if (cursor_index < number_of_bases) {
//       elaborated_shift_vmt += cursor->shift_vmt;
//       elaborated_shift_object += cursor->shift_object;
//       if (cursor->value == target_info)
//         elaborated_shift_target = elaborated_shift_object;
//       if (elaborated_shift_vmt == shift_vmt
//           && cursor->value == declared_info) {
//         if (elaborated_shift_target >= 0) {
//           *shift_object = elaborated_shift_target-elaborated_shift_object;
//           return 1;
//         };
//         break;
//       };
//       cursor = cursor->value->base_classes;
//       number_of_bases = cursor->value->number_of_base_classes;
//       cursor_index = 0;
//     };
//   } while (cursor_index < number_of_bases);
//   if (cursor_index >= number_of_bases)
//     return 0;
//   // elaborated_shift_target == -1 && cursor->value == target_info
//   //   && elaborated_shift_vmt == shift_vmt
//   return _frama_c_find_dynamic_cast_aux(target_info,
//     concrete_info->base_classes,
//     concrete_info->number_of_base_classes,
//     elaborated_shift_object, shift_vmt, -1, shift_object, &distance);
// }

/* statement */ list*
RTTITable::insertRTTIAlgorithmsPrelude(ForwardReferenceList& globals,
    location loc) {
  /* statement */ list* functionBody = insertRTTIAlgorithmsDeclPrelude(
      globals, loc);
  functionBody = insertRTTIAlgorithmsFirstPartPrelude(functionBody,
      loc);
  /* statement */ list* loopDoBody = insertRTTIAlgorithmsDoWhilePrelude(
      functionBody, loc);
  /* statement */ list* loopSecondWhileBody
    = insertRTTIAlgorithmsSecondWhilePrelude(loopDoBody, loc);
  insertRTTIAlgorithmsSecondWhileBodyPrelude(loopSecondWhileBody, loc);
  /* statement */ list* loopSecondIfThenBody
    = insertRTTIAlgorithmsSecondIfThenPrelude(loopDoBody, loc);
  insertRTTIAlgorithmsSecondIfThenBodyPrelude(loopSecondIfThenBody,
      loc);
  insertRTTIAlgorithmsLastPartPrelude(functionBody, loc);
  return functionBody;
}

void
RTTITable::insertVMTAndRttiPrelude(ForwardReferenceList& globals, location loc)
{ // globals types
  insertVMTContentPrelude(globals, loc);

  struct _frama_c_rtti_name_info_node;
  { globals.insertContainer(
      translation_unit_decl_Compound(
        copy_loc(loc),
        decl_or_impl_name_Implementation(
          qualified_name_cons(NULL, strdup("_frama_c_rtti_name_info_node"))),
        CSTRUCT, opt_none(),
        opt_none(), false, tkind_TStandard(), false, false));
  };
  
  insertVMTTypePrelude(globals, loc);
  insertRTTIInfoPrelude(globals, loc);
}

void
RTTITable::insertRttiPrelude(ForwardReferenceList& globals, location loc) {
  insertRTTIAlgorithmsAuxPrelude(globals, loc);
  insertRTTIAlgorithmsPrelude(globals, loc);
}

expression
RTTITable::getPvmt(const Clang_utils& utils, const clang::CXXRecordDecl* source,
    expression arg) const {
  const ClassInfo* sourceInfo = getClassInfo(source);
  assert(sourceInfo);
  const InheritancePath* accessToPvmt =
      sourceInfo->hasPvmtAsFirstField()
    ? NULL : &sourceInfo->getPvmtField();
  if (accessToPvmt) {
    InheritancePath::const_reverse_iterator
        iterEnd = accessToPvmt->rend(), iter = accessToPvmt->rbegin();
    for (; iter != iterEnd; ++iter) {
      const clang::CXXRecordDecl* baseClass = iter->first;
      tkind baseTemplate = utils.makeTemplateKind(baseClass);
      arg = expression_cons(copy_loc(arg->eloc),
        exp_node_PointerCast(qual_type_cons(NULL,
          typ_Pointer(pkind_PDataPointer(qual_type_cons(NULL,
            typ_Struct(utils.makeQualifiedName(*baseClass),
              baseTemplate))))),
          reference_or_pointer_kind_RPKStaticBasePointer(),
          arg));
    };
  };
  return expression_cons(copy_loc(arg->eloc),
    exp_node_Dereference(expression_cons(copy_loc(arg->eloc),
      exp_node_PointerCast(qual_type_cons(NULL, typ_Pointer(pkind_PDataPointer(
        qual_type_cons(NULL, typ_Pointer(pkind_PDataPointer(
          qual_type_cons(NULL, typ_Struct(qualified_name_cons(NULL,
            strdup("_frama_c_vmt")), tkind_TStandard())))))))),
      reference_or_pointer_kind_RPKPointer(), arg))));
}

void
RTTITable::addPvmtSetter(const Clang_utils& utils,
    const clang::CXXRecordDecl* source, /* statement */ list& insertionPoint, 
    location loc) {
  //   this->pvmt = &...::_frama_c_vmt_header;
  // translated into
  //   *((_frama_c_vmt**) this) = &...::_frama_c_vmt_header;
  const clang::CXXRecordDecl* currentClass = _currentClass.empty() ? NULL
      : _currentClass.front();
  assert(!currentClass || currentClass == source);
  const ClassInfo* currentClassInfo;
  if (currentClass != source) {
    currentClass = source;
    std::map<const clang::CXXRecordDecl*, ClassInfo>::const_iterator
      found = _classInfoTable.find(source);
    assert(found != _classInfoTable.end());
    currentClassInfo = &found->second;
  }
  else
    currentClassInfo = &_currentClassInfo.front();

  const clang::ClassTemplateSpecializationDecl* currentTSD = llvm::dyn_cast
    <clang::ClassTemplateSpecializationDecl>(currentClass);
  qualified_name vmtName = utils.makeQualifiedName(*currentClass);
  { /* qualification */ list* endQualif = &vmtName->prequalification;
    while (*endQualif) endQualif = &(*endQualif)->next;
    if (currentTSD)
      *endQualif = cons_container(qualification_QTemplateInstance(
          const_cast<char*>(vmtName->decl_name), utils
            .getTemplateExtension(currentTSD)), NULL);
    else
      *endQualif = cons_container(qualification_QStructOrClass(
          const_cast<char*>(vmtName->decl_name)), NULL);
  };
  vmtName->decl_name = strdup("_frama_c_vmt_header");
  const InheritancePath* accessToPvmt =
      currentClassInfo->hasPvmtAsFirstField()
    ? NULL : &currentClassInfo->getPvmtField();
  expression startPvmt = expression_cons(copy_loc(loc), exp_node_Variable(
     variable_FunctionParameter(strdup("this"))));
  if (accessToPvmt) {
    InheritancePath::const_reverse_iterator
        iterEnd = accessToPvmt->rend(), iter = accessToPvmt->rbegin();
    for (; iter != iterEnd; ++iter) {
      const clang::CXXRecordDecl* baseClass = iter->first;
      tkind baseTemplate = utils.makeTemplateKind(baseClass);
      startPvmt = expression_cons(copy_loc(loc),
        exp_node_PointerCast(qual_type_cons(NULL,
          typ_Pointer(pkind_PDataPointer(qual_type_cons(NULL,
            typ_Struct(utils.makeQualifiedName(*baseClass),
              baseTemplate))))),
          reference_or_pointer_kind_RPKStaticBasePointer(),
          startPvmt));
    };
  };
  // *((_frama_c_vmt **)this) = & ...::_frama_c_vmt_header;
  insertionPoint = cons_container(
    statement_Expression(copy_loc(loc), expression_cons(copy_loc(loc),
      exp_node_Assign(
        expression_cons(copy_loc(loc), exp_node_Dereference(
          expression_cons(copy_loc(loc), exp_node_PointerCast(
            qual_type_cons(NULL, typ_Pointer(pkind_PDataPointer(
              qual_type_cons(NULL, typ_Pointer(pkind_PDataPointer(
                qual_type_cons(NULL, typ_Struct(qualified_name_cons(NULL,
                  strdup("_frama_c_vmt")), tkind_TStandard())))))))),
            reference_or_pointer_kind_RPKPointer(), startPvmt)))),
        expression_cons(copy_loc(loc), exp_node_Address(
          expression_cons(copy_loc(loc), exp_node_Variable(
            variable_Global(vmtName)))))))), insertionPoint);
  list* endInsertionPoint = &insertionPoint->next;

  InheritancePosition::const_iterator derivationIterEnd =
    currentClassInfo->_derivationsPosition.end();
  int oldPosition = 0;
  for (InheritancePosition::const_iterator
         derivationIter = currentClassInfo->_derivationsPosition.begin();
       derivationIter != derivationIterEnd; ++derivationIter) {
    if (derivationIter->second > oldPosition) {
      oldPosition = derivationIter->second;
      qualified_name vmtNameShift = qualified_name_dup(vmtName);
      { std::ostringstream tmp;
        tmp << "_frama_c_vmt_header_for_shift_"
            << derivationIter->second;
        free(const_cast<char*>(vmtNameShift->decl_name));
        vmtNameShift->decl_name = strdup(tmp.str().c_str());
      };
      // *((_frama_c_vmt **) & this->_frama_c_...)
      //    = & __::_frama_c_vmt_header_for_shift_...;
      qualified_name baseName = utils.makeQualifiedName(*derivationIter->first);
      tkind derived_kind = utils.makeTemplateKind(derivationIter->first);
      *endInsertionPoint = cons_container(
        statement_Expression(copy_loc(loc), expression_cons(copy_loc(loc),
          exp_node_Assign(
            expression_cons(copy_loc(loc), exp_node_Dereference(
              expression_cons(copy_loc(loc), exp_node_PointerCast(
                qual_type_cons(NULL, typ_Pointer(pkind_PDataPointer(
                  qual_type_cons(NULL, typ_Pointer(pkind_PDataPointer(
                    qual_type_cons(NULL, typ_Struct(qualified_name_cons(NULL,
                      strdup("_frama_c_vmt")), tkind_TStandard())))))))),
                reference_or_pointer_kind_RPKPointer(),
                expression_cons(copy_loc(loc), exp_node_PointerCast(
                  qual_type_cons(NULL, typ_Pointer(pkind_PDataPointer(
                    qual_type_cons(NULL, typ_Struct(baseName, derived_kind))))),
                  reference_or_pointer_kind_RPKStaticBasePointer(),
                  expression_cons(copy_loc(loc), exp_node_Variable(
                        variable_FunctionParameter(strdup("this")))))))))),
          expression_cons(copy_loc(loc), exp_node_Address(
            expression_cons(copy_loc(loc), exp_node_Variable(
              variable_Global(vmtNameShift)))))))), *endInsertionPoint);
      endInsertionPoint = &((*endInsertionPoint)->next);
    };
  };

  if (!currentClassInfo->_virtualDerivationsPosition.empty()) {
    VirtualInheritancePosition::const_iterator iterEnd =
      currentClassInfo->_virtualDerivationsPosition.end(), iter;
    int oldPosition = 0;
    std::vector<const clang::CXXRecordDecl*>::const_iterator
      virtualBaseIterEnd = currentClassInfo->_virtualBaseClassTable.end(),
      virtualBaseIter = currentClassInfo->_virtualBaseClassTable.begin();
    for (iter = currentClassInfo->_virtualDerivationsPosition.begin();
         iter != iterEnd; ++iter) {
      assert(virtualBaseIter != virtualBaseIterEnd);
      if (*iter > oldPosition) {
        oldPosition = *iter;
        qualified_name vmtNameShift = qualified_name_dup(vmtName);
        { std::ostringstream tmp;
          tmp << "_frama_c_vmt_header_for_shift_" << *iter;
          free(const_cast<char*>(vmtNameShift->decl_name));
          vmtNameShift->decl_name = strdup(tmp.str().c_str());
        };
        // *((_frama_c_vmt **) & this->_frama_c_...)
        //    = & __::_frama_c_vmt_header_for_shift_...;
        qualified_name baseName = utils.makeQualifiedName(**virtualBaseIter);
        tkind virtual_kind = utils.makeTemplateKind(*virtualBaseIter);
        *endInsertionPoint = cons_container(
          statement_Expression(copy_loc(loc), expression_cons(copy_loc(loc),
            exp_node_Assign(
              expression_cons(copy_loc(loc), exp_node_Dereference(
                expression_cons(copy_loc(loc), exp_node_PointerCast(
                  qual_type_cons(NULL, typ_Pointer(pkind_PDataPointer(
                    qual_type_cons(NULL, typ_Pointer(pkind_PDataPointer(
                      qual_type_cons(NULL, typ_Struct(qualified_name_cons(NULL,
                        strdup("_frama_c_vmt")), tkind_TStandard())))))))),
                  reference_or_pointer_kind_RPKPointer(),
                  expression_cons(copy_loc(loc), exp_node_PointerCast(
                    qual_type_cons(
                      NULL,
                      typ_Pointer(
                        pkind_PDataPointer(
                          qual_type_cons(
                            NULL, typ_Struct(baseName, virtual_kind))))),
                      reference_or_pointer_kind_RPKVirtualBasePointer(
                        *iter,
                        qual_type_cons(NULL, typ_Pointer(pkind_PDataPointer(
                          qual_type_cons(NULL,
                          typ_Struct(
                            utils.makeQualifiedName(*currentClass),
                            tkind_dup(virtual_kind)))))),
                        false /* noeffect */),
                    expression_cons(copy_loc(loc), exp_node_Variable(
                          variable_FunctionParameter(strdup("this")))))))))),
            expression_cons(copy_loc(loc), exp_node_Address(
              expression_cons(copy_loc(loc), exp_node_Variable(
                variable_Global(vmtNameShift)))))))), *endInsertionPoint);
        endInsertionPoint = &((*endInsertionPoint)->next);
      };
      ++virtualBaseIter;
    };
  }
}

void
RTTITable::addBarePvmtSetter(const Clang_utils& utils,
    const clang::CXXRecordDecl* source, /* statement */ list& insertionPoint, 
    location loc) {
  const clang::CXXRecordDecl* currentClass = _currentClass.empty() ? NULL
      : _currentClass.front();
  assert(!currentClass || currentClass == source);
  const ClassInfo* currentClassInfo;
  if (currentClass != source) {
    currentClass = source;
    std::map<const clang::CXXRecordDecl*, ClassInfo>::const_iterator
      found = _classInfoTable.find(source);
    assert(found != _classInfoTable.end());
    currentClassInfo = &found->second;
  }
  else
    currentClassInfo = &_currentClassInfo.front();
  //   this->pvmt = &...::_frama_c_vmt_header;
  // translated into
  //   *((_frama_c_vmt**) this) = &...::_frama_c_vmt_header;
  const clang::ClassTemplateSpecializationDecl* currentTSD = llvm::dyn_cast
    <clang::ClassTemplateSpecializationDecl>(currentClass);
  qualified_name vmtName = utils.makeQualifiedName(*currentClass);
  { /* qualification */ list* endQualif = &vmtName->prequalification;
    while (*endQualif)
      endQualif = &(*endQualif)->next;
    if (currentTSD)
      *endQualif = cons_container(qualification_QTemplateInstance(
          const_cast<char*>(vmtName->decl_name), utils
            .getTemplateExtension(currentTSD)), NULL);
    else
      *endQualif = cons_container(qualification_QStructOrClass(
          const_cast<char*>(vmtName->decl_name)), NULL);
  };
  vmtName->decl_name = strdup("_frama_c_vmt");
  const InheritancePath* accessToPvmt = currentClassInfo->hasPvmtAsFirstField()
    ? NULL : &currentClassInfo->getPvmtField();

  expression startPvmt = expression_cons(copy_loc(loc), exp_node_Variable(
     variable_FunctionParameter(strdup("this"))));
  if (accessToPvmt) {
    InheritancePath::const_reverse_iterator
        iterEnd = accessToPvmt->rend(), iter = accessToPvmt->rbegin();
    for (; iter != iterEnd; ++iter) {
      const clang::CXXRecordDecl* baseClass = iter->first;
      tkind baseTemplate;
      if (baseClass->getKind() == clang::Decl::ClassTemplateSpecialization) {
        const clang::ClassTemplateSpecializationDecl* TSD = llvm::dyn_cast
          <clang::ClassTemplateSpecializationDecl>(baseClass);
        baseTemplate = tkind_TTemplateInstance(utils.getTemplateExtension(TSD));
      }
      else
        baseTemplate = tkind_TStandard();
      startPvmt = expression_cons(copy_loc(loc),
        exp_node_PointerCast(qual_type_cons(NULL,
          typ_Pointer(pkind_PDataPointer(qual_type_cons(NULL,
            typ_Struct(utils.makeQualifiedName(*baseClass),
              baseTemplate))))),
          reference_or_pointer_kind_RPKStaticBasePointer(),
          startPvmt));
    };
  };
  startPvmt = expression_cons(copy_loc(loc), exp_node_Dereference(
    expression_cons(copy_loc(loc), exp_node_PointerCast(
      qual_type_cons(NULL, typ_Pointer(pkind_PDataPointer(
        qual_type_cons(NULL, typ_Pointer(pkind_PDataPointer(
          qual_type_cons(NULL, typ_Struct(qualified_name_cons(NULL,
            strdup("_frama_c_vmt")), tkind_TStandard())))))))),
      reference_or_pointer_kind_RPKPointer(), startPvmt))));
  // int frama_c_vmt_index;
  insertionPoint = cons_container(
    statement_VarDecl(copy_loc(loc), strdup("frama_c_vmt_index"),
      qual_type_cons(NULL, typ_Int(IINT)), opt_none()), insertionPoint);
  list* endInsertionPoint = &insertionPoint->next;
  // for (frama_c_vmt_index = 0;
  //     frama_c_vmt_index < currentClass::numberOfMethods();
  //     ++frama_c_vmt_index)
  *endInsertionPoint = cons_container(
    statement_For(copy_loc(loc),
      init_statement_IExpression(expression_cons(copy_loc(loc),
        exp_node_Assign(expression_cons(copy_loc(loc),
          exp_node_Variable(variable_Local(qualified_name_cons(NULL,
            strdup("frama_c_vmt_index"))))), expression_cons(copy_loc(loc),
          exp_node_Constant(compilation_constant_IntCst(
            IINT, ICLITERAL, 0)))))),
      opt_some_container(expression_cons(copy_loc(loc),
        exp_node_Binary_operator(BOLESS, AKRVALUE,
          expression_cons(copy_loc(loc),
            exp_node_Variable(variable_Local(qualified_name_cons(NULL,
              strdup("frama_c_vmt_index"))))),
          makeIntLiteral(copy_loc(loc),IINT,
            (int) currentClassInfo->numberOfMethods())))),
      incr_statement_CExpression(expression_cons(copy_loc(loc),
        exp_node_Unary_operator(uokind_UOPreInc(),
          expression_cons(copy_loc(loc),
            exp_node_Variable(variable_Local(qualified_name_cons(NULL,
              strdup("frama_c_vmt_index")))))))),
      NULL /* body */, NULL), *endInsertionPoint);

  //   if (vmt_name::frama_c_vmt[frama_c_vmt_index]
  //       .method_ptr != (char*) 0) { ... }
  statement& forBody = ((statement) (*endInsertionPoint)->element.container)
      ->cons_statement.For.instruction;
  endInsertionPoint = &((*endInsertionPoint)->next);
  forBody =
    statement_Condition(
      copy_loc(loc),
      cond_statement_CondExpression(
        expression_cons(
          copy_loc(loc),
          exp_node_Binary_operator(
            BODIFFERENT, AKRVALUE,
            expression_cons(
              copy_loc(loc),
              exp_node_PointerCast(
                qual_type_cons(
                  NULL,
                  typ_Pointer(
                    pkind_PDataPointer(
                      qual_type_cons(NULL, typ_Int(ICHAR))))),
                reference_or_pointer_kind_RPKPointer(),
                expression_cons(
                  copy_loc(loc),
                  exp_node_FieldAccess(
                    expression_cons(
                      copy_loc(loc),
                      exp_node_Dereference(
                        expression_cons(
                          copy_loc(loc),
                          exp_node_Binary_operator(
                            BOPLUS, AKRVALUE,
                            expression_cons(
                              copy_loc(loc),
                              exp_node_Variable(
                                variable_Global(qualified_name_dup(vmtName)))),
                            expression_cons(
                              copy_loc(loc),
                              exp_node_Variable(
                                variable_Local(
                                  qualified_name_cons(
                                    NULL, strdup("frama_c_vmt_index"))))))))),
                    strdup("method_ptr"))))),
            makeNullPointer(loc, qual_type_cons(NULL, typ_Int(ICHAR)))))),
      statement_Block(copy_loc(loc), NULL) /* then_instruction */,
      statement_Nop(copy_loc(loc)) /* else_instruction */);
  /* statement */ list& ifBody = forBody->cons_statement.Condition
    .then_instruction->cons_statement.Block.instructions;
  //     startPvmt->table[frama_c_vmt_index].method_ptr
  //       = vmt_name::frama_c_vmt[frama_c_vmt_index].method_ptr;
  //     startPvmt->table[frama_c_vmt_index].shift_this
  //       = vmt_name::frama_c_vmt[frama_c_vmt_index].shift_this;
  ifBody = cons_container(statement_Expression(copy_loc(loc),
    expression_cons(copy_loc(loc), exp_node_Assign(
      expression_cons(copy_loc(loc),
        exp_node_FieldAccess(expression_cons(copy_loc(loc),
          exp_node_Dereference(expression_cons(copy_loc(loc),
            exp_node_Binary_operator(BOPLUS, AKRVALUE,
              expression_cons(copy_loc(loc),
                exp_node_FieldAccess(expression_cons(copy_loc(loc),
                  exp_node_Dereference(startPvmt)), "table")),
              expression_cons(copy_loc(loc),
                exp_node_Variable(variable_Local(qualified_name_cons(NULL,
                  strdup("frama_c_vmt_index"))))))))),
          "shift_this")),
      expression_cons(copy_loc(loc),
        exp_node_FieldAccess(expression_cons(copy_loc(loc),
          exp_node_Dereference(expression_cons(copy_loc(loc),
            exp_node_Binary_operator(BOPLUS, AKRVALUE,
              expression_cons(copy_loc(loc), exp_node_Variable(
                variable_Global(qualified_name_dup(vmtName)))),
              expression_cons(copy_loc(loc),
                exp_node_Variable(variable_Local(qualified_name_cons(NULL,
                  strdup("frama_c_vmt_index"))))))))),
          "shift_this"))))), ifBody);
  ifBody = cons_container(statement_Expression(copy_loc(loc),
    expression_cons(copy_loc(loc), exp_node_Assign(
      expression_cons(copy_loc(loc),
        exp_node_FieldAccess(expression_cons(copy_loc(loc),
          exp_node_Dereference(expression_cons(copy_loc(loc),
            exp_node_Binary_operator(BOPLUS, AKRVALUE,
              expression_cons(copy_loc(loc),
                exp_node_FieldAccess(expression_cons(copy_loc(loc),
                  exp_node_Dereference(expression_dup(startPvmt))), "table")),
              expression_cons(copy_loc(loc),
                exp_node_Variable(variable_Local(qualified_name_cons(NULL,
                  strdup("frama_c_vmt_index"))))))))),
          "method_ptr")),
      expression_cons(copy_loc(loc),
        exp_node_FieldAccess(expression_cons(copy_loc(loc),
          exp_node_Dereference(expression_cons(copy_loc(loc),
            exp_node_Binary_operator(BOPLUS, AKRVALUE,
              expression_cons(copy_loc(loc), exp_node_Variable(
                variable_Global(qualified_name_dup(vmtName)))),
              expression_cons(copy_loc(loc),
                exp_node_Variable(variable_Local(qualified_name_cons(NULL,
                  strdup("frama_c_vmt_index"))))))))),
          "method_ptr"))))), ifBody);
         

  InheritancePosition::const_iterator derivationIterEnd =
    currentClassInfo->_derivationsPosition.end();
  int oldPosition = 0;
  for (InheritancePosition::const_iterator
         derivationIter = currentClassInfo->_derivationsPosition.begin();
       derivationIter != derivationIterEnd; ++derivationIter) {
    if (derivationIter->second > oldPosition) {
      oldPosition = derivationIter->second;
      qualified_name vmtNameShift = qualified_name_dup(vmtName);
      { std::ostringstream tmp;
        tmp << "_frama_c_vmt_header_for_shift_"
            << derivationIter->second;
        free(const_cast<char*>(vmtNameShift->decl_name));
        vmtNameShift->decl_name = strdup(tmp.str().c_str());
      };
      qualified_name vmtNameHeader = qualified_name_dup(vmtName);
      free(const_cast<char*>(vmtNameHeader->decl_name));
      vmtNameHeader->decl_name = strdup("_frama_c_vmt_header");
      // *((_frama_c_vmt **) & this->_frama_c_...)
      //    = *((_frama_c_vmt **) & this)
      //      + (& __::_frama_c_vmt_header_for_shift_...
      //         - & __::_frama_c_vmt_header);
      qualified_name baseName = utils.makeQualifiedName(*derivationIter->first);
      const clang::ClassTemplateSpecializationDecl* TSD
        = llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(
            derivationIter->first);
      *endInsertionPoint = cons_container(
        statement_Expression(copy_loc(loc), expression_cons(copy_loc(loc),
          exp_node_Assign(
            expression_cons(copy_loc(loc), exp_node_Dereference(
              expression_cons(copy_loc(loc), exp_node_PointerCast(
                qual_type_cons(NULL, typ_Pointer(pkind_PDataPointer(
                  qual_type_cons(NULL, typ_Pointer(pkind_PDataPointer(
                    qual_type_cons(NULL, typ_Struct(qualified_name_cons(NULL,
                      strdup("_frama_c_vmt")), tkind_TStandard())))))))),
                reference_or_pointer_kind_RPKPointer(),
                expression_cons(copy_loc(loc), exp_node_PointerCast(
                  qual_type_cons(NULL, typ_Pointer(pkind_PDataPointer(
                    qual_type_cons(NULL, typ_Struct(baseName, !TSD
                      ? tkind_TStandard()
                      : tkind_TTemplateInstance(
                          utils.getTemplateExtension(TSD))))))),
                  reference_or_pointer_kind_RPKStaticBasePointer(),
                  expression_cons(copy_loc(loc), exp_node_Variable(
                    variable_FunctionParameter(strdup("this")))))))))),
          expression_cons(copy_loc(loc), exp_node_Binary_operator(
            BOPLUS, AKRVALUE,
            expression_dup(startPvmt),
            expression_cons(copy_loc(loc), exp_node_Binary_operator(
              BOMINUS, AKRVALUE,
              expression_cons(copy_loc(loc), exp_node_Address(
                expression_cons(copy_loc(loc), exp_node_Variable(
                  variable_Global(vmtNameShift))))),
              expression_cons(copy_loc(loc), exp_node_Address(
                expression_cons(copy_loc(loc), exp_node_Variable(
                  variable_Global(vmtNameHeader)))))))))))),
        *endInsertionPoint);
      endInsertionPoint = &((*endInsertionPoint)->next);
    };
  };
}

void
RTTITable::addPvmtSetterForBare(const Clang_utils& utils,
    const clang::CXXRecordDecl* source, /* statement */ list& insertionPoint, 
    location loc) {
  const clang::CXXRecordDecl* currentClass = _currentClass.empty() ? NULL
      : _currentClass.front();
  assert(!currentClass || currentClass == source);
  const ClassInfo* currentClassInfo;
  if (currentClass != source) {
    currentClass = source;
    std::map<const clang::CXXRecordDecl*, ClassInfo>::const_iterator
      found = _classInfoTable.find(source);
    assert(found != _classInfoTable.end());
    currentClassInfo = &found->second;
  }
  else
    currentClassInfo = &_currentClassInfo.front();

  //   this->pvmt = &...::_frama_c_vmt_header;
  // translated into
  //   *((_frama_c_vmt**) this) = &...::_frama_c_vmt_header;
  const clang::ClassTemplateSpecializationDecl* currentTSD = llvm::dyn_cast
    <clang::ClassTemplateSpecializationDecl>(currentClass);
  qualified_name vmtName = utils.makeQualifiedName(*currentClass);
  { /* qualification */ list* endQualif = &vmtName->prequalification;
    while (*endQualif)
      endQualif = &(*endQualif)->next;
    if (currentTSD)
      *endQualif = cons_container(qualification_QTemplateInstance(
          const_cast<char*>(vmtName->decl_name), utils
            .getTemplateExtension(currentTSD)), NULL);
    else
      *endQualif = cons_container(qualification_QStructOrClass(
          const_cast<char*>(vmtName->decl_name)), NULL);
    vmtName->decl_name = NULL;
  };
  const InheritancePath* accessToPvmt = currentClassInfo->hasPvmtAsFirstField()
    ? NULL : &currentClassInfo->getPvmtField();

  expression startPvmt = expression_cons(copy_loc(loc), exp_node_Variable(
     variable_FunctionParameter(strdup("this"))));
  if (accessToPvmt) {
    InheritancePath::const_reverse_iterator
        iterEnd = accessToPvmt->rend(), iter = accessToPvmt->rbegin();
    for (; iter != iterEnd; ++iter) {
      const clang::CXXRecordDecl* baseClass = iter->first;
      tkind baseTemplate;
      if (baseClass->getKind() == clang::Decl::ClassTemplateSpecialization) {
        const clang::ClassTemplateSpecializationDecl* TSD = llvm::dyn_cast
          <clang::ClassTemplateSpecializationDecl>(baseClass);
        baseTemplate = tkind_TTemplateInstance(utils.getTemplateExtension(TSD));
      }
      else
        baseTemplate = tkind_TStandard();
      startPvmt = expression_cons(copy_loc(loc),
        exp_node_PointerCast(qual_type_cons(NULL,
          typ_Pointer(pkind_PDataPointer(qual_type_cons(NULL,
            typ_Struct(utils.makeQualifiedName(*baseClass),
              baseTemplate))))),
          reference_or_pointer_kind_RPKStaticBasePointer(),
          startPvmt));
    };
  };
  startPvmt = expression_cons(copy_loc(loc), exp_node_Dereference(
    expression_cons(copy_loc(loc), exp_node_PointerCast(
      qual_type_cons(NULL, typ_Pointer(pkind_PDataPointer(
        qual_type_cons(NULL, typ_Pointer(pkind_PDataPointer(
          qual_type_cons(NULL, typ_Struct(qualified_name_cons(NULL,
            strdup("_frama_c_vmt")), tkind_TStandard())))))))),
      reference_or_pointer_kind_RPKPointer(), startPvmt))));
  // int frama_c_vmt_index;
  insertionPoint = cons_container(
    statement_VarDecl(copy_loc(loc), strdup("frama_c_vmt_index"),
      qual_type_cons(NULL, typ_Int(IINT)), opt_none()), insertionPoint);
  list* endInsertionPoint = &insertionPoint->next;
  // struct _frama_c_vmt_content _frama_c_local_vmt[2];
  *endInsertionPoint = cons_container(
    statement_VarDecl(copy_loc(loc), strdup("_frama_c_local_vmt"),
      qual_type_cons(NULL, typ_Array(akind_cons(qual_type_cons(NULL,
        typ_Struct(qualified_name_cons(NULL, strdup("_frama_c_vmt_content")),
          tkind_TStandard())),
        opt_some_container(makeIntLiteral(copy_loc(loc), IINT,
          (int) currentClassInfo->numberOfMethods()))))),
      opt_none()), *endInsertionPoint);
  endInsertionPoint = &(*endInsertionPoint)->next;

  // struct _frama_c_vmt _frama_c_local_vmt_header = 
  // {.table = _frama_c_local_vmt,
  //  .table_size = currentClassInfo.numberOfMethods(),
  //  .rtti_info = & currentClass::_frama_c_rtti_name_info};
  vmtName->decl_name = strdup("_frama_c_rtti_name_info");
  *endInsertionPoint = cons_container(
    statement_VarDecl(copy_loc(loc), strdup("_frama_c_local_vmt_header"),
      qual_type_cons(NULL,
        typ_Struct(qualified_name_cons(NULL, strdup("_frama_c_vmt")),
          tkind_TStandard())),
      opt_some_container(init_expr_Compound_init(
        cons_container(
          init_expr_Single_init(expression_cons(copy_loc(loc),
            exp_node_Variable(variable_Local(
              qualified_name_cons(NULL, strdup("_frama_c_local_vmt")))))),
        cons_container(
          init_expr_Single_init(makeIntLiteral(copy_loc(loc), IINT,
            (int) currentClassInfo->numberOfMethods())),
        cons_container(
          init_expr_Single_init(expression_cons(copy_loc(loc),
            exp_node_Address(expression_cons(copy_loc(loc),
              exp_node_Variable(variable_Global(vmtName)))))),
          NULL)))))), *endInsertionPoint);
  endInsertionPoint = &(*endInsertionPoint)->next;

  // for (frama_c_vmt_index = 0;
  //     frama_c_vmt_index < sizeof(currentClass::numberOfMethods());
  //     ++frama_c_vmt_index)
  *endInsertionPoint = cons_container(
    statement_For(copy_loc(loc),
      init_statement_IExpression(expression_cons(copy_loc(loc),
        exp_node_Assign(expression_cons(copy_loc(loc),
          exp_node_Variable(variable_Local(qualified_name_cons(NULL,
            strdup("frama_c_vmt_index"))))), expression_cons(copy_loc(loc),
          exp_node_Constant(compilation_constant_IntCst(
            IINT, ICLITERAL, 0)))))),
      opt_some_container(expression_cons(copy_loc(loc),
        exp_node_Binary_operator(BOLESS, AKRVALUE,
          expression_cons(copy_loc(loc),
            exp_node_Variable(variable_Local(qualified_name_cons(NULL,
              strdup("frama_c_vmt_index"))))),
          makeIntLiteral(copy_loc(loc),IINT,
            (int) currentClassInfo->numberOfMethods())))),
      incr_statement_CExpression(expression_cons(copy_loc(loc),
        exp_node_Unary_operator(uokind_UOPreInc(),
          expression_cons(copy_loc(loc),
            exp_node_Variable(variable_Local(qualified_name_cons(NULL,
              strdup("frama_c_vmt_index")))))))),
      NULL /* body */, NULL), *endInsertionPoint);
  statement& forBody = ((statement) (*endInsertionPoint)->element.container)
      ->cons_statement.For.instruction;
  endInsertionPoint = &((*endInsertionPoint)->next);

  //   (_frama_c_local_vmt + frama_c_vmt_index)->method_ptr
  //     = currentClass::_frama_c_vmt[frama_c_vmt_index].method_ptr;
  //   (_frama_c_local_vmt + frama_c_vmt_index)->shift_this
  //     = currentClass::_frama_c_vmt[frama_c_vmt_index].shift_this;
  vmtName = qualified_name_dup(vmtName);
  free(const_cast<char*>(vmtName->decl_name));
  vmtName->decl_name = strdup("_frama_c_vmt");
  forBody = statement_Block(copy_loc(loc), NULL);

  forBody->cons_statement.Block.instructions
    = cons_container(statement_Expression(copy_loc(loc),
      expression_cons(copy_loc(loc), exp_node_Assign(
        expression_cons(copy_loc(loc),
          exp_node_FieldAccess(expression_cons(copy_loc(loc),
            exp_node_Dereference(expression_cons(copy_loc(loc),
              exp_node_Binary_operator(BOPLUS, AKRVALUE,
                expression_cons(copy_loc(loc),
                  exp_node_Variable(variable_Local(qualified_name_cons(NULL,
                    "_frama_c_local_vmt")))),
                expression_cons(copy_loc(loc),
                  exp_node_Variable(variable_Local(qualified_name_cons(NULL,
                    strdup("frama_c_vmt_index"))))))))),
            "shift_this")),
        expression_cons(copy_loc(loc),
          exp_node_FieldAccess(expression_cons(copy_loc(loc),
            exp_node_Dereference(expression_cons(copy_loc(loc),
              exp_node_Binary_operator(BOPLUS, AKRVALUE,
                expression_cons(copy_loc(loc), exp_node_Variable(
                  variable_Global(qualified_name_dup(vmtName)))),
                expression_cons(copy_loc(loc),
                  exp_node_Variable(variable_Local(qualified_name_cons(NULL,
                    strdup("frama_c_vmt_index"))))))))),
            "shift_this"))))), forBody->cons_statement.Block.instructions);
  forBody->cons_statement.Block.instructions
    = cons_container(statement_Expression(copy_loc(loc),
      expression_cons(copy_loc(loc), exp_node_Assign(
        expression_cons(copy_loc(loc),
          exp_node_FieldAccess(expression_cons(copy_loc(loc),
            exp_node_Dereference(expression_cons(copy_loc(loc),
              exp_node_Binary_operator(BOPLUS, AKRVALUE,
                expression_cons(copy_loc(loc),
                  exp_node_Variable(variable_Local(qualified_name_cons(NULL,
                    "_frama_c_local_vmt")))),
                expression_cons(copy_loc(loc),
                  exp_node_Variable(variable_Local(qualified_name_cons(NULL,
                    strdup("frama_c_vmt_index"))))))))),
            "method_ptr")),
        expression_cons(copy_loc(loc),
          exp_node_FieldAccess(expression_cons(copy_loc(loc),
            exp_node_Dereference(expression_cons(copy_loc(loc),
              exp_node_Binary_operator(BOPLUS, AKRVALUE,
                expression_cons(copy_loc(loc), exp_node_Variable(
                  variable_Global(qualified_name_dup(vmtName)))),
                expression_cons(copy_loc(loc),
                  exp_node_Variable(variable_Local(qualified_name_cons(NULL,
                    strdup("frama_c_vmt_index"))))))))),
            "method_ptr"))))), forBody->cons_statement.Block.instructions);
  // *((struct _frama_c_vmt **)this) = &_frama_c_local_vmt_header;
  *endInsertionPoint = cons_container(
    statement_Expression(copy_loc(loc), expression_cons(copy_loc(loc),
      exp_node_Assign(
        startPvmt,
        expression_cons(copy_loc(loc), exp_node_Address(
          expression_cons(copy_loc(loc), exp_node_Variable(variable_Local(
            qualified_name_cons(NULL, "_frama_c_local_vmt_header"))))))))),
    *endInsertionPoint);
  endInsertionPoint = &(*endInsertionPoint)->next;

  InheritancePosition::const_iterator derivationIterEnd =
    currentClassInfo->_derivationsPosition.end();
  int oldPosition = 0;
  for (InheritancePosition::const_iterator
         derivationIter = currentClassInfo->_derivationsPosition.begin();
       derivationIter != derivationIterEnd; ++derivationIter) {
    if (derivationIter->second > oldPosition) {
      oldPosition = derivationIter->second;

      // struct _frama_c_vmt_content* _frama_c_local_vmt_for_shift_index
      //   = &_frama_c_local_vmt[base_index];
      char* localVmtName;
      { std::ostringstream tmp;
        tmp << "_frama_c_local_vmt_for_shift_" << derivationIter->second;
        localVmtName = strdup(tmp.str().c_str());
      };
      *endInsertionPoint = cons_container(statement_VarDecl(copy_loc(loc),
        localVmtName,
        qual_type_cons(NULL, typ_Pointer(pkind_PDataPointer(
          qual_type_cons(NULL, typ_Struct(qualified_name_cons(NULL,
            strdup("_frama_c_vmt_content")), tkind_TStandard()))))),
        opt_some_container(init_expr_Single_init(expression_cons(copy_loc(loc),
          exp_node_Binary_operator(BOPLUS, AKRVALUE,
            expression_cons(copy_loc(loc), exp_node_Variable(variable_Local(
              qualified_name_cons(NULL, strdup("_frama_c_local_vmt"))))),
            makeIntLiteral(copy_loc(loc), IINT, derivationIter->second)))))),
        *endInsertionPoint);
      endInsertionPoint = &(*endInsertionPoint)->next;

      // struct _frama_c_vmt _frama_c_local_vmt_header_for_shift_index =
      // {.table = & _frama_c_local_vmt[base_index],
      //  .table_size = baseClass.numberOfMethods(),
      //  .rtti_info = & currentClass::_frama_c_rtti_name_info};
      { std::ostringstream tmp;
        tmp << "_frama_c_local_vmt_header_for_shift_" << derivationIter->second;
        localVmtName = strdup(tmp.str().c_str());
      };
      vmtName = qualified_name_dup(vmtName);
      free(const_cast<char*>(vmtName->decl_name));
      vmtName->decl_name = strdup("_frama_c_rtti_name_info");
      *endInsertionPoint = cons_container(statement_VarDecl(copy_loc(loc),
        localVmtName,
        qual_type_cons(NULL, typ_Struct(qualified_name_cons(NULL,
          strdup("_frama_c_vmt")), tkind_TStandard())),
        opt_some_container(init_expr_Compound_init(
          cons_container(
            init_expr_Single_init(expression_cons(copy_loc(loc),
              exp_node_Binary_operator(BOPLUS, AKRVALUE,
                expression_cons(copy_loc(loc), exp_node_Variable(
                 variable_Local(qualified_name_cons(NULL,
                   strdup("_frama_c_local_vmt"))))),
                makeIntLiteral(copy_loc(loc), IINT, derivationIter->second)))),
          cons_container(
            init_expr_Single_init(makeIntLiteral(copy_loc(loc), IINT,
              getClassInfo(derivationIter->first)->numberOfMethods())),
          cons_container(
            init_expr_Single_init(expression_cons(copy_loc(loc),
              exp_node_Address(expression_cons(copy_loc(loc),
                exp_node_Variable(variable_Global(vmtName)))))),
            NULL)))))), *endInsertionPoint);
      endInsertionPoint = &(*endInsertionPoint)->next;

      // *((struct _frama_c_vmt **)(& this->baseClassAccess))
      //   = &_frama_c_local_vmt_header_for_shift_index;
      const clang::ClassTemplateSpecializationDecl* TSD
        = llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(
            derivationIter->first);
      *endInsertionPoint = cons_container(statement_Expression(copy_loc(loc),
        expression_cons(copy_loc(loc), exp_node_Assign(
            getPvmt(utils, derivationIter->first,
              expression_cons(copy_loc(loc), exp_node_PointerCast(
                qual_type_cons(NULL, typ_Pointer(pkind_PDataPointer(
                  qual_type_cons(NULL, typ_Struct(
                    utils.makeQualifiedName(*derivationIter->first),
                    TSD ? tkind_TTemplateInstance(
                            utils.getTemplateExtension(TSD))
                        : tkind_TStandard()))))),
                reference_or_pointer_kind_RPKStaticBasePointer(),
                expression_cons(copy_loc(loc), exp_node_Variable(
                  variable_FunctionParameter(strdup("this"))))))),
          expression_cons(copy_loc(loc), exp_node_Address(
            expression_cons(copy_loc(loc), exp_node_Variable(
              variable_Local(qualified_name_cons(NULL,
                strdup(localVmtName)))))))))), *endInsertionPoint);
      endInsertionPoint = &(*endInsertionPoint)->next;
    };
  };
}

void
RTTITable::insertStaticVMTDeclaration(ForwardReferenceList& classContent,
    location classLoc) {
  // struct _frama_c_vmt_content _frama_c_vmt[];
  int size = _currentClassInfo.front().numberOfMethods();
  // Kernel won't like a 0-sized array;
  if (size == 0) size = 1;
  classContent.getFront() =
    cons_container(
      class_decl_CFieldDecl(
        copy_loc(classLoc),
        strdup("_frama_c_vmt"),
        qual_type_cons(
          cons_plain(STATIC, NULL),
          typ_Array(
            akind_cons(
              qual_type_cons(
                NULL,
                typ_Struct(
                  qualified_name_cons(
                    NULL, strdup("_frama_c_vmt_content")),
                  tkind_TStandard())),
              opt_some_container(makeIntLiteral(classLoc,IINT, size))))),
        opt_none(),
        false),
      classContent.getFront());
}


void
RTTITable::insertStaticBaseClassesDeclaration(
    ForwardReferenceList& classContent, location classLoc) {
  if (!_currentClassInfo.front()._derivationsPosition.empty()
      || !_currentClassInfo.front()._virtualDerivationsPosition.empty()) {
    // struct _frama_c_rtti_name_info_content _frama_c_base_classes[];
    expression size =
      makeIntLiteral(
        classLoc,
        IINT,
        _currentClassInfo.front()._virtualDerivationsPosition.size()
        + _currentClassInfo.front()._derivationsPosition.size());
    classContent.getFront() =
      cons_container(
        class_decl_CFieldDecl(
          copy_loc(classLoc),
          strdup("_frama_c_base_classes"),
          qual_type_cons(
            cons_plain(STATIC, NULL),
            typ_Array(
              akind_cons(
                qual_type_cons(
                  NULL,
                  typ_Struct(
                    qualified_name_cons(
                      NULL, strdup("_frama_c_rtti_name_info_content")),
                    tkind_TStandard())),
                opt_some_container(size)))),
          opt_none(),
          false),
        classContent.getFront());
  };
}

void
RTTITable::insertStaticRTTIDeclaration(ForwardReferenceList& classContent,
    location classLoc) {
    // struct _frama_c_rtti_name_info_node _frama_c_rtti_name_info;
    classContent.getFront() = cons_container(
      class_decl_CFieldDecl(
        copy_loc(classLoc),
        strdup("_frama_c_rtti_name_info"),
        qual_type_cons(
          cons_plain(STATIC, NULL),
          typ_Struct(
            qualified_name_cons(
              NULL,
              strdup("_frama_c_rtti_name_info_node")), tkind_TStandard())),
        opt_none(),
        false),
      classContent.getFront());
}

void
RTTITable::insertStaticVMTHeaderDeclaration(ForwardReferenceList& classContent,
    location classLoc) {
  if (!_currentClassInfo.front()._virtualDerivationsPosition.empty()) {
    VirtualInheritancePosition::const_reverse_iterator iterEnd
      = _currentClassInfo.front()._virtualDerivationsPosition.rend(), iter;
    for (iter =  _currentClassInfo.front()._virtualDerivationsPosition.rbegin();
        iter != iterEnd; ++iter) {
      // struct _frama_c_vmt _frama_c_vmt_header_for_shift_...;
      std::ostringstream vmtName;
      vmtName << "_frama_c_vmt_header_for_shift_" << *iter;
      classContent.getFront() =
        cons_container(
          class_decl_CFieldDecl(
            copy_loc(classLoc),
            copy_string(vmtName.str()),
            qual_type_cons(
              cons_plain(STATIC, NULL),
              typ_Struct(
                qualified_name_cons(NULL, strdup("_frama_c_vmt")),
                tkind_TStandard())),
            opt_none(),
            false),
        classContent.getFront());
    };
  };
  InheritancePath::const_reverse_iterator derivationIterEnd =
    _currentClassInfo.front()._derivationsPosition.rend();
  for (InheritancePath::const_reverse_iterator derivationIter =
         _currentClassInfo.front()._derivationsPosition.rbegin();
       derivationIter != derivationIterEnd;
       ++derivationIter) {
    if (derivationIter->second != 0) {
      // struct _frama_c_vmt _frama_c_vmt_header_for_shift_...;
      std::ostringstream vmtName;
      vmtName << "_frama_c_vmt_header_for_shift_"
              << derivationIter->second;
      classContent.getFront() = cons_container(
        class_decl_CFieldDecl(
          copy_loc(classLoc),
          copy_string(vmtName.str()),
          qual_type_cons(
            cons_plain(STATIC, NULL),
            typ_Struct(
              qualified_name_cons(NULL, strdup("_frama_c_vmt")),
              tkind_TStandard())),
          opt_none(),
          false),
        classContent.getFront());
    };
  };
  // struct _frama_c_vmt _frama_c_vmt_header;
  classContent.getFront() = cons_container(
    class_decl_CFieldDecl(
      copy_loc(classLoc),
      strdup("_frama_c_vmt_header"),
      qual_type_cons(
        cons_plain(STATIC, NULL),
        typ_Struct(
          qualified_name_cons(
            NULL, strdup("_frama_c_vmt")), tkind_TStandard())),
      opt_none(),
      false),
    classContent.getFront());
}

bool
RTTITable::retrieveStaticInheritancePathBetween(
    const clang::CXXRecordDecl* derived, const clang::CXXRecordDecl* base,
    RTTITable::InheritancePath& result, const Clang_utils& utils,
    RTTITable::VirtualInheritancePath* virtualResult) const {
  typedef clang::CXXRecordDecl::base_class_const_iterator base_iterator;
  typedef std::vector<std::pair<std::pair<base_iterator, int>, base_iterator> >
      path_t;
  path_t path;
  std::vector<std::pair<const clang::CXXRecordDecl*, int> > virtualPath;
  bool hasResult = false;
  // depth first visit of the hierarchy, store the current branch into path.
  // as soon as base is found, path is used to create result.
  path.push_back(std::make_pair(
    std::make_pair(derived->bases_begin(), 0), derived->bases_end()));
  while (true) {
    base_iterator* sonIterEnd = &path.back().second,
                 * sonIter = &path.back().first.first;
    bool doesContinue = (*sonIter != *sonIterEnd);
    if (doesContinue) { // descent to first son
      const clang::CXXRecordDecl* baseDecl = (*sonIter)->getType()
          .getTypePtr()->getAsCXXRecordDecl();
      if (!baseDecl) {
        ++(*sonIter);
        doesContinue = (*sonIter != *sonIterEnd);
      }
      else {
        bool isVirtual = (*sonIter)->isVirtual();
        int position =
          getBasePosition(
            path.size() > 1
              ? path[path.size()-2].first.first->getType().getTypePtr()
                  ->getAsCXXRecordDecl()
              : derived, baseDecl, isVirtual);
        if (isVirtual) {
          if (!virtualResult) {
             ++(*sonIter);
             doesContinue = (*sonIter != *sonIterEnd);
          }
          else
            virtualPath.push_back(std::make_pair(baseDecl, position));
        }
        else if (!baseDecl->isPolymorphic())
          position = 0; // instead of -1 or 0
        if (!isVirtual || virtualResult) {
          if (baseDecl == base) {
            if (!hasResult) {
              hasResult = true;
              path_t::const_iterator iterPathEnd = path.end(),
                                     iterPath = path.begin();
              const clang::CXXRecordDecl* virtualBase = virtualPath.empty()
                  ? NULL : virtualPath.back().first;
              bool hasFoundBase = virtualBase == NULL;
              for (; iterPath != iterPathEnd; ++iterPath) {
                const clang::CXXRecordDecl* base = iterPath->first.first
                    ->getType().getTypePtr()->getAsCXXRecordDecl();
                if (hasFoundBase)
                  result.push_back(std::make_pair(base,iterPath->first.second));
                else if (base == virtualBase)
                  hasFoundBase = true;
              };
              assert(hasFoundBase && (!virtualBase || virtualResult));
              if (virtualBase)
                *virtualResult = std::make_pair(virtualBase,
                    virtualPath.back().second);
            }
            else
              assert(false);
            ++(*sonIter);
            if (isVirtual)
              virtualPath.pop_back();
            doesContinue = (*sonIter != *sonIterEnd);
          }
          else
            path.push_back(std::make_pair(
              std::make_pair(baseDecl->bases_begin(), position /* 0 */),
              baseDecl->bases_end()));
        };
      };
    };
    if (!doesContinue) {
      // set to next uncle
      path.pop_back();
      if (hasResult)
        return true;
      if (path.empty())
        return false;
      sonIterEnd = &path.back().second;
      sonIter = &path.back().first.first;
      const clang::CXXRecordDecl* baseDecl =
        (*sonIter)->getType().getTypePtr()->getAsCXXRecordDecl();
      assert(baseDecl);
      if ((*sonIter)->isVirtual()) {
        assert(!virtualPath.empty());
        virtualPath.pop_back();
      };
      ++(*sonIter);
      if (*sonIter != *sonIterEnd) {
        const clang::CXXRecordDecl* baseDecl = (*sonIter)->getType()
            .getTypePtr()->getAsCXXRecordDecl();
        if (!baseDecl)
          ++(*sonIter);
        else {
          bool isVirtual = (*sonIter)->isVirtual();
          int position =
            getBasePosition(
              path.size() > 1
                ? path[path.size()-2].first.first->getType().getTypePtr()
                    ->getAsCXXRecordDecl()
                : derived, baseDecl, isVirtual);
          if (isVirtual) {
            if (!virtualResult)
              ++(*sonIter);
            else
              virtualPath.push_back(std::make_pair(baseDecl, position));
          }
          else if (!baseDecl->isPolymorphic())
            position = 0;
          if (!isVirtual || virtualResult) {
            path.back().first.second = position;
            if (baseDecl == base) {
              if (!hasResult) {
                hasResult = true;
                path_t::const_iterator iterPathEnd = path.end(),
                                       iterPath = path.begin();
                const clang::CXXRecordDecl* virtualBase = virtualPath.empty()
                    ? NULL : virtualPath.back().first;
                bool hasFoundBase = virtualBase == NULL;
                for (; iterPath != iterPathEnd; ++iterPath) {
                  const clang::CXXRecordDecl* base = iterPath->first.first
                      ->getType().getTypePtr()->getAsCXXRecordDecl();
                  if (hasFoundBase)
                    result.push_back(std::make_pair(base,
                          iterPath->first.second));
                  else if (base == virtualBase)
                    hasFoundBase = true;
                };
                assert(!virtualBase || virtualResult);
                if (virtualBase)
                  *virtualResult = std::make_pair(virtualBase,
                      virtualPath.back().second);
              }
              else
                assert(false);
              ++(*sonIter);
              if (isVirtual)
                virtualPath.pop_back();
            };
          }
        };
      };
    };
  };
}

void
RTTITable::retrieveInheritancePathBetween(const clang::CXXRecordDecl* derived,
    const clang::CXXRecordDecl* base, RTTITable::InheritancePath& result,
    RTTITable::VirtualInheritancePath& virtualResult,
    const Clang_utils& utils) const
{ std::map<const clang::CXXRecordDecl*, ClassInfo>::const_iterator
    found = _classInfoTable.find(derived);
  if (found != _classInfoTable.end() && found->second.hasVirtualBaseClasses())
  { std::vector<const clang::CXXRecordDecl*>::const_iterator
      iter = found->second._virtualBaseClassTable.begin(),
      iterEnd = found->second._virtualBaseClassTable.end();
    int index = -1;
    for (; iter != iterEnd; ++iter) {
      ++index;
      if (*iter == base) {
        virtualResult.first = base;
        virtualResult.second = found->second._virtualDerivationsPosition[index];
        return;
      };
      if (retrieveStaticInheritancePathBetween(*iter, base, result, utils)) {
        virtualResult.first = *iter;
        virtualResult.second = found->second._virtualDerivationsPosition[index];
        return;
      };
    }
  }
  
  bool ok = retrieveStaticInheritancePathBetween(derived, base, result, utils,
      &virtualResult);
  assert(ok);
}

qualified_name
RTTITable::insertStaticVMTDefinition(const Clang_utils& utils,
    ForwardReferenceList& globals, location classLoc) {
  // declaration of the static variable before the class
  // struct _frama_c_vmt_content ...::_frama_c_vmt[size] = { ... };
  qualified_name vmtName = specialMemberName(utils, "_frama_c_vmt");
  translation_unit_decl framaCVMTDeclaration;
  globals.insertContainer(
    framaCVMTDeclaration =
    translation_unit_decl_GlobalVarDecl(
      copy_loc(classLoc),
      decl_or_impl_name_Implementation(vmtName),
      qual_type_cons(
        NULL,
        typ_Array(
          akind_cons(
            qual_type_cons(
              NULL,
              typ_Struct(
                qualified_name_cons(
                  NULL, strdup("_frama_c_vmt_content")), tkind_TStandard())),
            opt_some_container(
              makeIntLiteral(
                classLoc,
                IINT,
                (int) _currentClassInfo.front().numberOfMethods()))))),
      opt_some_container(init_expr_Compound_init(NULL)), false,false));
  /* init_expr */ ForwardReferenceList framaCVMTInitializationEnd(
    *(/* init_expr */ list*) &framaCVMTDeclaration
      ->cons_translation_unit_decl.GlobalVarDecl.init->content.container);

  tkind frontTemplate = utils.makeTemplateKind(_currentClass.front());
  ClassInfo::MethodIterator iterEnd = _currentClassInfo.front().endOfMethods();
  // int numberOfMethods = 0;
  for (ClassInfo::MethodIterator iter = _currentClassInfo.front()
      .beginOfMethods(); iter != iterEnd; ++iter) {
    init_expr methodInitialization;
    framaCVMTInitializationEnd.insertContainer(methodInitialization
      = init_expr_Compound_init(NULL));
    /* init_expr */ ForwardReferenceList framaCMethodInitialization(
      *&methodInitialization->cons_init_expr.Compound_init.init_elts);
    if (iter->isMethod()) {
      const clang::CXXMethodDecl* def = iter->getMethod();
      // _frama_c_vmt[numberOfMethods].method_ptr
      //   = (void (*)()) &makeQualifiedName(*iter->getMethod());
      framaCMethodInitialization.insertContainer(init_expr_Single_init(
        expression_cons(copy_loc(classLoc), exp_node_PointerCast(
          qual_type_cons(NULL, typ_Pointer(pkind_PFunctionPointer(
            signature_cons(qual_type_cons(NULL, typ_Void()), NULL,
             true /* variadic */)))),
          reference_or_pointer_kind_RPKPointer(),
          expression_cons(
            copy_loc(classLoc),
            exp_node_Address(
              expression_cons(
                copy_loc(classLoc),
                exp_node_Variable(
                  variable_CodePointer(
                    utils.makeQualifiedName(*def),
                    utils.makeSignature(*def),
                    (def->getKind() == clang::Decl::CXXDestructor)
                    ? funkind_FKDestructor(true)
                    : utils.cv_meth(def),
                    false /* is_extern_c */,
                    tkind_TStandard())))))))));
    }
    else // iter->isVirtualBaseAccess()
      framaCMethodInitialization.insertContainer(
        init_expr_Single_init(
          expression_cons(
            copy_loc(classLoc),
            exp_node_PointerCast(
              qual_type_cons(
                NULL,
                typ_Pointer(
                  pkind_PFunctionPointer(
                    signature_cons(
                      qual_type_cons(NULL, typ_Void()), NULL, false)))),
              reference_or_pointer_kind_RPKPointer(),
              makeIntLiteral(classLoc,IINT,0)))));
    expression shiftToTableTarget = NULL;
    if (!iter->getInheritancePath().empty()
        || iter->hasVirtualInheritancePath()) {
      shiftToTableTarget =
        makeNullPointer(
          classLoc,
          qual_type_cons(
            NULL,
            typ_Struct(
              utils.makeQualifiedName(*_currentClass.front()),
              tkind_dup(frontTemplate))));

      if (iter->hasVirtualInheritancePath()) {
        const VirtualInheritancePath& path = iter->getVirtualInheritancePath();
        const clang::CXXRecordDecl* targetTableClass = path.first;
        tkind targetTemplate = utils.makeTemplateKind(targetTableClass);
        shiftToTableTarget = expression_cons(copy_loc(classLoc),
          exp_node_PointerCast(qual_type_cons(NULL,
            typ_Pointer(pkind_PDataPointer(qual_type_cons(NULL,
              typ_Struct(utils.makeQualifiedName(*targetTableClass),
                targetTemplate))))),
            reference_or_pointer_kind_RPKStaticBasePointer(),
            // reference_or_pointer_kind_RPKStaticVirtualBasePointer(
            //   path.second,
            //   qual_type_cons(NULL, typ_Struct(utils.makeQualifiedName
            //     (*_currentClass.front()), tkind_dup(frontTemplate)),
            //   true /* noeffect */)),
            shiftToTableTarget));
      };
      InheritancePath::const_reverse_iterator
          targetIterEnd = iter->getInheritancePath().rend(),
          targetIter = iter->getInheritancePath().rbegin();
      for (; targetIter != targetIterEnd; ++targetIter) {
        const clang::CXXRecordDecl* targetTableClass = targetIter->first;
        tkind targetTemplate = utils.makeTemplateKind(targetTableClass);
        // qual_type derivedType = NULL;
        shiftToTableTarget = expression_cons(copy_loc(classLoc),
          exp_node_PointerCast(qual_type_cons(NULL,
            typ_Pointer(pkind_PDataPointer(qual_type_cons(NULL,
              typ_Struct(utils.makeQualifiedName(*targetTableClass),
                targetTemplate))))),
            reference_or_pointer_kind_RPKStaticBasePointer(),
            shiftToTableTarget));
      };
    };

    bool isMethod = iter->isMethod();
    // _frama_c_vmt_content[numberOfMethods].shift_this
    //   = (void*) (((_currentClass*) 0)->_frama_c_sub target)
    //     - (void*) (((_currentClass*) 0)->_frama_c_sub iter)
    const clang::CXXRecordDecl* classMethod = isMethod
        ? iter->getMethod()->getParent() : NULL;
    if (isMethod &&
        classMethod->getDefinition() == _currentClass.front()->getDefinition())
    { if (!shiftToTableTarget)
        framaCMethodInitialization.insertContainer(
          init_expr_Single_init(makeIntLiteral(classLoc,IINT,0)));
      else
        framaCMethodInitialization.insertContainer(
          init_expr_Single_init(
            expression_cons(
              copy_loc(classLoc),
              exp_node_Binary_operator(
                BOMINUS, AKRVALUE,
                expression_cons(
                  copy_loc(classLoc),
                  exp_node_PointerCast(
                    qual_type_cons(NULL, utils.charPtrType()),
                    reference_or_pointer_kind_RPKPointer(),
                    shiftToTableTarget)),
                makeNullPointer(classLoc, utils.charQualType())))));
    }
    else {
      exp_node nodeResult;
      if (isMethod) {
        tkind methodClassTemplate = utils.makeTemplateKind(classMethod);
        InheritancePath inheritancePath;
        VirtualInheritancePath virtualInheritancePath(NULL, 0);
        retrieveInheritancePathBetween(_currentClass.front(), classMethod,
            inheritancePath, virtualInheritancePath, utils);
        int sizeInheritancePath = inheritancePath.size()-1;
        assert(sizeInheritancePath >= 0 || virtualInheritancePath.first);
        nodeResult =
          exp_node_PointerCast(
            qual_type_cons(
              NULL,
              typ_Pointer(
                pkind_PDataPointer(
                  qual_type_cons(
                    NULL,
                    typ_Struct(
                      utils.makeQualifiedName(*classMethod),
                      methodClassTemplate))))),
            reference_or_pointer_kind_RPKStaticBasePointer(),
            makeNullPointer(
              classLoc,
              qual_type_cons(
                NULL,
                typ_Struct(
                  utils.makeQualifiedName(*_currentClass.front()),
                  tkind_dup(frontTemplate)))));
        if (virtualInheritancePath.first  && sizeInheritancePath >= 0) {
          const clang::CXXRecordDecl *localBase = virtualInheritancePath.first;
          // const clang::CXXRecordDecl *localDerived = _currentClass.front();
          tkind base_kind = utils.makeTemplateKind(localBase);
          // tkind derived_kind = utils.makeTemplateKind(localDerived);
          qual_type localBaseType = qual_type_cons(NULL,
            typ_Pointer(pkind_PDataPointer(qual_type_cons(NULL,
              typ_Struct(utils.makeQualifiedName(*localBase), base_kind)))));
          // qual_type localDerivedType =
          //   qual_type_cons(
          //     NULL,
          //     typ_Pointer(
          //       pkind_PDataPointer(
          //         qual_type_cons(
          //           NULL,
          //           typ_Struct(
          //          utils.makeQualifiedName(*localDerived), derived_kind)))));
          exp_node tmpResult =
            exp_node_PointerCast(
              localBaseType,
              reference_or_pointer_kind_RPKStaticBasePointer(),
              expression_cons(copy_loc(classLoc), nodeResult));
          qual_type tmp = nodeResult->cons_exp_node.PointerCast.cast_type;
          nodeResult->cons_exp_node.PointerCast.cast_type
            = tmpResult->cons_exp_node.PointerCast.cast_type;
          tmpResult->cons_exp_node.PointerCast.cast_type = tmp;
          nodeResult = tmpResult;
        };
        for (int index = 0; index < sizeInheritancePath; ++index) {
          const clang::CXXRecordDecl
            *localBase = inheritancePath[index].first;
          // const clang::CXXRecordDecl
          //   *localDerived = inheritancePath[index+1].first;
          tkind base_kind = utils.makeTemplateKind(localBase);
          qual_type localBaseType = qual_type_cons(NULL,
            typ_Pointer(pkind_PDataPointer(qual_type_cons(NULL,
              typ_Struct(utils.makeQualifiedName(*localBase), base_kind)))));
          exp_node tmpResult = exp_node_PointerCast(
            localBaseType,
            reference_or_pointer_kind_RPKStaticBasePointer(),
            expression_cons(copy_loc(classLoc), nodeResult));
          qual_type tmp = nodeResult->cons_exp_node.PointerCast.cast_type;
          nodeResult->cons_exp_node.PointerCast.cast_type
            = tmpResult->cons_exp_node.PointerCast.cast_type;
          tmpResult->cons_exp_node.PointerCast.cast_type = tmp;
          nodeResult = tmpResult;
        };
      }
      else {
        nodeResult =
          makeNullPointer(
            classLoc,
            qual_type_cons(
              NULL,
              typ_Struct(
                utils.makeQualifiedName(*_currentClass.front()),
                tkind_dup(frontTemplate))))->econtent;
        if (!iter->getParentInheritancePath().empty()) {
          InheritancePath::const_reverse_iterator
            pathIterEnd = iter->getParentInheritancePath().rend(),
            pathIter = iter->getParentInheritancePath().rbegin();
          for (; pathIter != pathIterEnd; ++pathIter) {
            const clang::CXXRecordDecl
              *localBase = pathIter->first;
            const clang::ClassTemplateSpecializationDecl* TSD = llvm::
                dyn_cast<clang::ClassTemplateSpecializationDecl>(localBase);
            qual_type localBaseType = qual_type_cons(NULL,
              typ_Pointer(pkind_PDataPointer(qual_type_cons(NULL,
                typ_Struct(utils.makeQualifiedName(*localBase),
                  !TSD ? tkind_TStandard() : tkind_TTemplateInstance(utils
                    .getTemplateExtension(TSD)))))));
            nodeResult = exp_node_PointerCast(
              localBaseType,
              reference_or_pointer_kind_RPKStaticBasePointer(),
              expression_cons(copy_loc(classLoc), nodeResult));
          };
        };
      };

      if (!shiftToTableTarget)
        framaCMethodInitialization.insertContainer(
          init_expr_Single_init(
            expression_cons(
              copy_loc(classLoc),
              exp_node_Binary_operator(
                BOMINUS, AKRVALUE,
                makeNullPointer(classLoc,utils.charQualType()),
                expression_cons(
                  copy_loc(classLoc),
                  exp_node_PointerCast(
                    qual_type_cons(NULL, utils.charPtrType()),
                    reference_or_pointer_kind_RPKPointer(),
                    expression_cons(copy_loc(classLoc), nodeResult)))))));
      else // targetTableClass && external def
        framaCMethodInitialization.insertContainer(init_expr_Single_init(
          expression_cons(copy_loc(classLoc),
            exp_node_Binary_operator(BOMINUS, AKRVALUE,
              expression_cons(copy_loc(classLoc), exp_node_PointerCast(
                qual_type_cons(NULL, utils.charPtrType()),
                reference_or_pointer_kind_RPKPointer(), shiftToTableTarget)),
              expression_cons(copy_loc(classLoc), exp_node_PointerCast(
                qual_type_cons(NULL, utils.charPtrType()),
                reference_or_pointer_kind_RPKPointer(),
                expression_cons(copy_loc(classLoc), nodeResult)))))));
    };
    // ++numberOfMethods;
  };
  free_tkind(frontTemplate);
  return vmtName;
}

void
RTTITable::addBareToQualification(qualified_name& name) const {
  /* qualification */ list endQualif = name->prequalification;
  assert(endQualif);
  while (endQualif->next)
    endQualif = endQualif->next;
  const char** className = NULL;
  if (_currentClass.front()->getKind()
        != clang::Decl::ClassTemplateSpecialization) {
    assert(((qualification) endQualif->element.container)->tag_qualification
        == QSTRUCTORCLASS);
    className = &((qualification) endQualif->element.container)
      ->cons_qualification.QStructOrClass.name;
  }
  else {
    assert(((qualification) endQualif->element.container)->tag_qualification
        == QTEMPLATEINSTANCE);
    className = &((qualification) endQualif->element.container)
      ->cons_qualification.QTemplateInstance.name;
  };
  const char* suffix = "_frama_c_bare";
  int classNameLength = strlen(*className), suffixLength = strlen(suffix);
  char* newName = (char*) malloc(classNameLength+suffixLength+1);
  memcpy(newName, *className, classNameLength);
  memcpy(newName + classNameLength, suffix, suffixLength+1);
  free(const_cast<char*>(*className));
  *className = newName;
}

qualified_name
RTTITable::insertStaticBaseClassesDefinition(const Clang_utils& utils,
      ForwardReferenceList& globals, location classLoc) {
  if (_currentClassInfo.front()._derivationsPosition.empty()
      && _currentClassInfo.front()._virtualDerivationsPosition.empty())
    return NULL;
  // struct _frama_c_rtti_name_info_content _frama_c_base_classes[] = { ... };
  qualified_name nameBaseClasses =
    specialMemberName(utils,"_frama_c_base_classes");
  expression size =
    makeIntLiteral(
      classLoc,
      IINT,
      _currentClassInfo.front()._virtualDerivationsPosition.size()
      + _currentClassInfo.front()._derivationsPosition.size());
  translation_unit_decl framaCBaseClassesDeclaration =
    translation_unit_decl_GlobalVarDecl(
      copy_loc(classLoc), decl_or_impl_name_Implementation(nameBaseClasses),
      qual_type_cons(
        NULL,
        typ_Array(
          akind_cons(
            qual_type_cons(
              NULL,
              typ_Struct(
                qualified_name_cons(
                  NULL, strdup("_frama_c_rtti_name_info_content")),
                tkind_TStandard())),
            opt_some_container(size)))),
      opt_some_container(init_expr_Compound_init(NULL)), false, false);
  globals.insertContainer(framaCBaseClassesDeclaration);
  /* init_expr */ ForwardReferenceList framaCBaseClassesDeclarationEnd(
    *(/* init_expr */ list*) &framaCBaseClassesDeclaration
      ->cons_translation_unit_decl.GlobalVarDecl.init->content.container);
  tkind frontTemplate = utils.makeTemplateKind(_currentClass.front());
  InheritancePosition::const_iterator
    derivationIterEnd = _currentClassInfo.front()._derivationsPosition.end();
  for (InheritancePosition::const_iterator derivationIter =
         _currentClassInfo.front()._derivationsPosition.begin();
       derivationIter != derivationIterEnd; ++derivationIter) {
    // struct _frama_c_rtti_name_info_content {
    //   struct _frama_c_rtti_name_info_node* value;
    //   int shift_object; 
    //   int shift_vmt; 
    // };
    qualified_name nameBaseValue = utils.makeQualifiedName(
      *derivationIter->first);
    tkind templateParameters = utils.makeTemplateKind(derivationIter->first);
    /* qualification */ list* endQualif = &nameBaseValue->prequalification;
    while (*endQualif) endQualif = &(*endQualif)->next;
    if (templateParameters->tag_tkind == TSTANDARD)
      *endQualif =
        cons_container(
          qualification_QStructOrClass(
            const_cast<char*>(nameBaseValue->decl_name)), NULL);
    else {
      tkind temp = tkind_dup(templateParameters);
      assert(temp->tag_tkind == TTEMPLATEINSTANCE);
      *endQualif =
        cons_container(
          qualification_QTemplateInstance(
            const_cast<char*>(nameBaseValue->decl_name),
            temp->cons_tkind.TTemplateInstance.parameters), NULL);
      free(temp);
    };
    nameBaseValue->decl_name = strdup("_frama_c_rtti_name_info");
    init_expr baseClassInitialization;
    framaCBaseClassesDeclarationEnd.insertContainer(baseClassInitialization
      = init_expr_Compound_init(NULL));
    /* init_expr */ ForwardReferenceList framaCBaseClassInitialization(
      baseClassInitialization->cons_init_expr.Compound_init.init_elts);
    // _frama_c_base_classes[derivationIter].value = 
    //   &derivationIter->first::_frama_c_rtti_name_info
    framaCBaseClassInitialization.insertContainer(init_expr_Single_init(
      expression_cons(copy_loc(classLoc), exp_node_Address(
        expression_cons(copy_loc(classLoc), exp_node_Variable(variable_Global(
          nameBaseValue)))))));
    // _frama_c_base_classes[derivationIter].shift_object = 
    //   (void*) 0 - (void*) ((derivationIter->first*) (_currentClass*) 0)
    framaCBaseClassInitialization.insertContainer(
      init_expr_Single_init(
        expression_cons(
          copy_loc(classLoc),
          exp_node_Binary_operator(
            BOMINUS, AKRVALUE,
            makeNullPointer(classLoc, utils.charQualType()),
            expression_cons(
              copy_loc(classLoc),
              exp_node_PointerCast(
                qual_type_cons(NULL, utils.charPtrType()),
                reference_or_pointer_kind_RPKPointer(),
                expression_cons(
                  copy_loc(classLoc),
                  exp_node_PointerCast(
                    qual_type_cons(
                      NULL,
                      typ_Pointer(
                        pkind_PDataPointer(
                          qual_type_cons(
                            NULL,
                            typ_Struct(
                              utils.makeQualifiedName(*derivationIter->first),
                              templateParameters))))),
                    reference_or_pointer_kind_RPKStaticBasePointer(),
                    makeNullPointer(
                      classLoc,
                      qual_type_cons(
                        NULL,
                        typ_Struct(
                          utils.makeQualifiedName(*_currentClass.front()),
                          tkind_dup(frontTemplate))))))))))));
    framaCBaseClassInitialization.insertContainer(
      init_expr_Single_init(
        makeIntLiteral(classLoc,IINT,derivationIter->second)));
  };
  if (!_currentClassInfo.front()._virtualDerivationsPosition.empty()) {
    translation_unit_decl framaCBareBaseClassesDeclaration
      = translation_unit_decl_dup(framaCBaseClassesDeclaration);
    addBareToQualification(framaCBareBaseClassesDeclaration
        ->cons_translation_unit_decl.GlobalVarDecl.name
          ->cons_decl_or_impl_name.Implementation.name);
    globals.insertContainer(framaCBareBaseClassesDeclaration);

    VirtualInheritancePosition::const_iterator
      virtualDerivationIterEnd
        = _currentClassInfo.front()._virtualDerivationsPosition.end(),
      virtualDerivationIter
        = _currentClassInfo.front()._virtualDerivationsPosition.begin();
    int virtualIndex = 0;
    for (; virtualDerivationIter != virtualDerivationIterEnd;
        ++virtualDerivationIter) {
      // struct _frama_c_rtti_name_info_content {
      //   struct _frama_c_rtti_name_info_node* value;
      //   int shift_object; 
      //   int shift_vmt; 
      // };
      const clang::CXXRecordDecl* baseClass = _currentClassInfo.front()
        ._virtualBaseClassTable[virtualIndex];

      qualified_name nameBaseValue = utils.makeQualifiedName(*baseClass);
      tkind templateParameters = utils.makeTemplateKind(baseClass);
      /* qualification */ list* endQualif = &nameBaseValue->prequalification;
      while (*endQualif)
        endQualif = &(*endQualif)->next;
      if (templateParameters->tag_tkind == TSTANDARD)
        *endQualif =
          cons_container(
            qualification_QStructOrClass(
              const_cast<char*>(nameBaseValue->decl_name)), NULL);
      else {
        tkind temp = tkind_dup(templateParameters);
        assert(temp->tag_tkind == TTEMPLATEINSTANCE);
        *endQualif =
          cons_container(
            qualification_QTemplateInstance(
              const_cast<char*>(nameBaseValue->decl_name),
              temp->cons_tkind.TTemplateInstance.parameters),NULL);
        free(temp);
      };
      nameBaseValue->decl_name = strdup("_frama_c_rtti_name_info");
      init_expr baseClassInitialization;
      framaCBaseClassesDeclarationEnd.insertContainer(baseClassInitialization
        = init_expr_Compound_init(NULL));
      /* init_expr */ ForwardReferenceList framaCBaseClassInitialization(
        baseClassInitialization->cons_init_expr.Compound_init.init_elts);
      // _frama_c_base_classes[*virtualDerivationIter].value = 
      //   &derivationIter->first::_frama_c_rtti_name_info
      framaCBaseClassInitialization.insertContainer(init_expr_Single_init(
        expression_cons(copy_loc(classLoc), exp_node_Address(
          expression_cons(copy_loc(classLoc), exp_node_Variable(variable_Global(
            nameBaseValue)))))));
      // _frama_c_base_classes[*virtualDerivationIter].shift_object = 
      //   (void*) 0 - (void*) ((_virtualBaseClassTable[virtualIndex]*)
      //     (_currentClass*) 0)
      framaCBaseClassInitialization.insertContainer(
        init_expr_Single_init(
          expression_cons(
            copy_loc(classLoc),
            exp_node_Binary_operator(
              BOMINUS, AKRVALUE,
              makeNullPointer(classLoc,utils.charQualType()),
              expression_cons(
                copy_loc(classLoc),
                exp_node_PointerCast(
                  qual_type_cons(NULL, utils.charPtrType()),
                  reference_or_pointer_kind_RPKPointer(),
                  expression_cons(
                    copy_loc(classLoc),
                    exp_node_PointerCast(
                      qual_type_cons(
                        NULL,
                        typ_Pointer(
                          pkind_PDataPointer(
                            qual_type_cons(
                              NULL,
                              typ_Struct(
                                utils.makeQualifiedName(
                                  * _currentClassInfo.front()
                                  ._virtualBaseClassTable[virtualIndex]),
                                templateParameters))))),
                      reference_or_pointer_kind_RPKStaticBasePointer(),
                      makeNullPointer(
                        classLoc,
                        qual_type_cons(
                          NULL,
                          typ_Struct(
                            utils.makeQualifiedName(*_currentClass.front()),
                            tkind_dup(frontTemplate))))))))))));
      // _frama_c_base_classes[derivationIter].shift_vmt=*virtualDerivationIter;
      framaCBaseClassInitialization.insertContainer(
        init_expr_Single_init(
          makeIntLiteral(classLoc,IINT,*virtualDerivationIter)));
      ++virtualIndex;
    };
  };

  free_tkind(frontTemplate);
  return nameBaseClasses;
}

void
RTTITable::insertDeclStaticVMTHeaderDefinition(ForwardReferenceList& globals,
    location classLoc, qualified_name vmtName) {
  // struct _frama_c_vmt ...::_frama_c_vmt_header;
  qualified_name vmtHeaderName = qualified_name_dup(vmtName);
  free(const_cast<char*>(vmtHeaderName->decl_name));
  vmtHeaderName->decl_name = strdup("_frama_c_vmt_header");
  globals.insertContainer(
    translation_unit_decl_GlobalVarDecl(
      copy_loc(classLoc), decl_or_impl_name_Implementation(vmtHeaderName),
      qual_type_cons(
        NULL,
        typ_Struct(
          qualified_name_cons(NULL, strdup("_frama_c_vmt")),
          tkind_TStandard())),
      opt_none(), false, false));

  if (!_currentClassInfo.front()._virtualDerivationsPosition.empty()) {
    vmtHeaderName = qualified_name_dup(vmtName);
    free(const_cast<char*>(vmtHeaderName->decl_name));
    vmtHeaderName->decl_name = strdup("_frama_c_vmt_header");
    addBareToQualification(vmtHeaderName);
    globals.insertContainer(
      translation_unit_decl_GlobalVarDecl(
        copy_loc(classLoc), decl_or_impl_name_Implementation(vmtHeaderName),
        qual_type_cons(
          NULL,
          typ_Struct(
            qualified_name_cons(NULL, strdup("_frama_c_vmt")),
            tkind_TStandard())),
        opt_none(), false, false));
  };
}

void RTTITable::insertStaticEmptyRTTIDefinition(
  const Clang_utils& utils, ForwardReferenceList& globals, location classLoc) {
  qualified_name nameRtti = specialMemberName(utils, "_frama_c_rtti_name_info");
  const char* class_name =
    strdup(_currentClass.front()->getName().str().c_str());
  qual_type rttiInfo =
    qual_type_cons(
      NULL,
      typ_Struct(
        qualified_name_cons(NULL, strdup("_frama_c_rtti_name_info_node")),
        tkind_TStandard()));
  /* list is built in reverse order. */
  /* first field is pvmt */
  /* init_expr */ list rttiInit =
    cons_container(
      init_expr_Single_init(
        makeNullPointer(
          classLoc,
          makeStructType(qualified_name_cons(NULL,strdup("_frama_c_vmt"))))),
      NULL);
  /* number_of_base_classes */
  rttiInit =
    cons_container(
      init_expr_Single_init(makeIntLiteral(classLoc,IINT,0)),rttiInit);
  /* base_classes */
  rttiInit =
    cons_container(
      init_expr_Single_init(
        makeNullPointer(
          classLoc,
          makeStructType(
            qualified_name_cons(
              NULL,strdup("_frama_c_rtti_name_info_content"))))),
      rttiInit);
  /* name */
  rttiInit =
    cons_container(
      init_expr_Single_init(makeStringLiteral(classLoc, class_name)),rttiInit);
  
  translation_unit_decl rttiDef =
    translation_unit_decl_GlobalVarDecl(
      copy_loc(classLoc),
      decl_or_impl_name_Implementation(nameRtti),
      rttiInfo,
      opt_some_container(init_expr_Compound_init(rttiInit)),
      false, false);

  globals.insertContainer(rttiDef);
      
}

qualified_name
RTTITable::insertStaticRTTIDefinition(const Clang_utils& utils,
    ForwardReferenceList& globals, location classLoc,
    qualified_name vmtName, qualified_name nameBaseClasses) {
  // struct _frama_c_rtti_name_info_node _frama_c_rtti_name_info = { ... }
  qualified_name nameRtti = specialMemberName(utils,"_frama_c_rtti_name_info");
  const char* class_name =
    strdup(_currentClass.front()->getName().str().c_str());
  translation_unit_decl nameRttiInitialization =
    translation_unit_decl_GlobalVarDecl(
      copy_loc(classLoc),
      decl_or_impl_name_Implementation(nameRtti),
      qual_type_cons(
        NULL,
        typ_Struct(
          qualified_name_cons(NULL, strdup("_frama_c_rtti_name_info_node")),
          tkind_TStandard())),
      opt_some_container(init_expr_Compound_init(NULL)),
      false,
      false);
  globals.insertContainer(nameRttiInitialization);
  ForwardReferenceList framaCNameRttiInitialization(
    *(/* init_expr */ list*) &nameRttiInitialization
      ->cons_translation_unit_decl.GlobalVarDecl.init->content.container);
  // struct _frama_c_rtti_name_info_node {
  //   const char* name;
  //   struct _frama_c_rtti_name_info_content* base_classes;
  //   int number_of_base_classes;
  //   struct _frama_c_vmt* pvmt;
  // };

  // _frama_c_rtti_name_info.name = "nameRtti->decl_name";
  framaCNameRttiInitialization.insertContainer(
    init_expr_Single_init(makeStringLiteral(classLoc,class_name)));
  // _frama_c_rtti_name_info.base_classes
  //   = (struct _frama_c_rtti_name_info_content*) _frama_c_base_classes;
  if (!nameBaseClasses)
    framaCNameRttiInitialization.insertContainer(
      init_expr_Single_init(
        makeNullPointer(
          classLoc,
          makeStructType(
            qualified_name_cons(
              NULL, strdup("_frama_c_rtti_name_info_content"))))));
  else
    framaCNameRttiInitialization.insertContainer(init_expr_Single_init(
      expression_cons(copy_loc(classLoc), exp_node_PointerCast(
        qual_type_cons(NULL, typ_Pointer(pkind_PDataPointer(
          qual_type_cons(NULL, typ_Struct(qualified_name_cons(NULL,
            strdup("_frama_c_rtti_name_info_content")), tkind_TStandard()))))),
        reference_or_pointer_kind_RPKPointer(),
        expression_cons(copy_loc(classLoc), exp_node_Variable(
          variable_Global(qualified_name_dup(nameBaseClasses))))))));

  // _frama_c_rtti_name_info.number_of_base_classes
  //     = _currentClassInfo._derivationsPosition.size();
  //     + _currentClassInfo._virtualDerivationsPosition.size();
  framaCNameRttiInitialization.insertContainer(
    init_expr_Single_init(
      makeIntLiteral(
        classLoc,
        IINT,
        _currentClassInfo.front()._derivationsPosition.size()
        + _currentClassInfo.front()._virtualDerivationsPosition.size())));
  // _frama_c_rtti_name_info.pvmt = vmtHeaderName;
  qualified_name vmtHeaderName = qualified_name_dup(vmtName);
  free(const_cast<char*>(vmtHeaderName->decl_name));
  vmtHeaderName->decl_name = strdup("_frama_c_vmt_header");
  framaCNameRttiInitialization.insertContainer(init_expr_Single_init(
    expression_cons(copy_loc(classLoc), exp_node_Address(
      expression_cons(copy_loc(classLoc), exp_node_Variable(
        variable_Global(vmtHeaderName)))))));

  if (!_currentClassInfo.front()._virtualDerivationsPosition.empty()) {
    qualified_name bareNameRtti = qualified_name_dup(nameRtti);
    addBareToQualification(bareNameRtti);
    assert(nameBaseClasses);
    qualified_name bareNameBaseClasses = qualified_name_dup(nameBaseClasses);
    addBareToQualification(bareNameBaseClasses);
    nameRttiInitialization =
      translation_unit_decl_GlobalVarDecl(
        copy_loc(classLoc),
        decl_or_impl_name_Implementation(bareNameRtti),
        qual_type_cons(
          NULL,
          typ_Struct(
            qualified_name_cons(NULL, strdup("_frama_c_rtti_name_info_node")),
            tkind_TStandard())),
        opt_some_container(init_expr_Compound_init(NULL)),
        false,
        false);
    globals.insertContainer(nameRttiInitialization);
    ForwardReferenceList framaCNameRttiInitialization(
      *(/* init_expr */ list*) &nameRttiInitialization
        ->cons_translation_unit_decl.GlobalVarDecl.init->content.container);
    
    // _frama_c_rtti_name_info.name = "bareNameRtti->decl_name";
    framaCNameRttiInitialization.insertContainer(init_expr_Single_init(
      expression_cons(copy_loc(classLoc), exp_node_String(
        copy_string(std::string(class_name) + "_frama_c_bare")))));
    // _frama_c_rtti_name_info.base_classes
    //   = (struct _frama_c_rtti_name_info_content*) _frama_c_base_classes;
    framaCNameRttiInitialization.insertContainer(init_expr_Single_init(
      expression_cons(copy_loc(classLoc), exp_node_PointerCast(
        qual_type_cons(NULL, typ_Pointer(pkind_PDataPointer(
          qual_type_cons(NULL, typ_Struct(qualified_name_cons(NULL,
            strdup("_frama_c_rtti_name_info_content")), tkind_TStandard()))))),
        reference_or_pointer_kind_RPKPointer(),
        expression_cons(copy_loc(classLoc), exp_node_Variable(
          variable_Global(bareNameBaseClasses)))))));

    // _frama_c_rtti_name_info.number_of_base_classes
    //     = _currentClassInfo._derivationsPosition.size();
    framaCNameRttiInitialization.insertContainer(
      init_expr_Single_init(
        makeIntLiteral(
          classLoc,
          IINT,
          _currentClassInfo.front()._derivationsPosition.size())));
    // _frama_c_rtti_name_info.pvmt = vmtHeaderName;
    vmtHeaderName = qualified_name_dup(vmtName);
    free(const_cast<char*>(vmtHeaderName->decl_name));
    vmtHeaderName->decl_name = strdup("_frama_c_vmt_header");
    addBareToQualification(vmtHeaderName);
    framaCNameRttiInitialization.insertContainer(init_expr_Single_init(
      expression_cons(copy_loc(classLoc), exp_node_Address(
        expression_cons(copy_loc(classLoc), exp_node_Variable(
          variable_Global(vmtHeaderName)))))));
  };
  return nameRtti;
}

void
RTTITable::insertStaticVMTHeaderDefinition(const Clang_utils& utils,
    ForwardReferenceList& globals, location classLoc, qualified_name vmtName,
    qualified_name nameRtti) {
  // struct _frama_c_vmt ...::_frama_c_vmt_header = {
  //    (struct _frama_c_vmt_content*) _frama_c_vmt,
  //    _currentClassInfo.numberOfMethods(),
  //    &_frama_c_rtti_name_info
  // };
  qualified_name vmtHeaderName = qualified_name_dup(vmtName);
  free(const_cast<char*>(vmtHeaderName->decl_name));
  vmtHeaderName->decl_name = strdup("_frama_c_vmt_header");
  globals.insertContainer(
    translation_unit_decl_GlobalVarDecl(
      copy_loc(classLoc),
      decl_or_impl_name_Implementation(vmtHeaderName),
      qual_type_cons(
        NULL,
        typ_Struct(
          qualified_name_cons(NULL, strdup("_frama_c_vmt")),
          tkind_TStandard())),
      opt_some_container(
        init_expr_Compound_init(
          cons_container(
            init_expr_Single_init(
              expression_cons(
                copy_loc(classLoc),
                exp_node_PointerCast(
                  qual_type_cons(
                    NULL,
                    typ_Pointer(
                      pkind_PDataPointer(
                        qual_type_cons(
                          NULL,
                          typ_Struct(
                            qualified_name_cons(
                              NULL, strdup("_frama_c_vmt_content")),
                            tkind_TStandard()))))),
                  reference_or_pointer_kind_RPKPointer(),
                  expression_cons(
                    copy_loc(classLoc),
                    exp_node_Variable(
                      variable_Global(qualified_name_dup(vmtName))))))),
            cons_container(
              init_expr_Single_init(
                makeIntLiteral(
                  classLoc,
                  IINT,
                  _currentClassInfo.front().numberOfMethods())),
              cons_container(
                init_expr_Single_init(
                  expression_cons(
                    copy_loc(classLoc),
                    exp_node_Address(
                      expression_cons(
                        copy_loc(classLoc),
                        exp_node_Variable(
                          variable_Global(qualified_name_dup(nameRtti))))))),
                NULL))))),
      false,
      false));
  InheritancePath::const_iterator derivationIterEnd =
    _currentClassInfo.front()._derivationsPosition.end(), derivationIter;
  int shift = 0;
  for (derivationIter = _currentClassInfo.front()._derivationsPosition.begin();
       derivationIter != derivationIterEnd; ++derivationIter) {
    int previousShift = shift;
    shift = derivationIter->second;
    if (shift>previousShift) {
      qualified_name vmtHeaderShiftName = qualified_name_dup(vmtName);
      { std::ostringstream tmp;
        tmp << "_frama_c_vmt_header_for_shift_" << shift;
        free(const_cast<char*>(vmtHeaderShiftName->decl_name));
        vmtHeaderShiftName->decl_name = copy_string(tmp.str());
      };
      globals.insertContainer(
        translation_unit_decl_GlobalVarDecl(
          copy_loc(classLoc),
          decl_or_impl_name_Implementation(vmtHeaderShiftName),
          qual_type_cons(
            NULL,
            typ_Struct(
              qualified_name_cons(NULL, strdup("_frama_c_vmt")),
              tkind_TStandard())),
          opt_some_container(
            init_expr_Compound_init(
              cons_container(
                init_expr_Single_init(
                  expression_cons(
                    copy_loc(classLoc),
                    exp_node_Binary_operator(
                      BOPLUS, AKRVALUE,
                      expression_cons(
                        copy_loc(classLoc),
                        exp_node_PointerCast(
                          qual_type_cons(
                            NULL,
                            typ_Pointer(
                              pkind_PDataPointer(
                                qual_type_cons(
                                  NULL,
                                  typ_Struct(
                                    qualified_name_cons(
                                      NULL, strdup("_frama_c_vmt_content")),
                                    tkind_TStandard()))))),
                          reference_or_pointer_kind_RPKPointer(),
                          expression_cons(
                            copy_loc(classLoc),
                            exp_node_Variable(
                              variable_Global(qualified_name_dup(vmtName)))))),
                      makeIntLiteral(classLoc,IINT,shift)))),
                cons_container(
                  init_expr_Single_init(
                    makeIntLiteral(
                      classLoc,
                      IINT,
                      _currentClassInfo.front().numberOfMethods()-shift)),
                  cons_container(
                    init_expr_Single_init(
                      expression_cons(
                        copy_loc(classLoc),
                        exp_node_Address(
                          expression_cons(
                            copy_loc(classLoc),
                            exp_node_Variable(
                              variable_Global(
                                qualified_name_dup(nameRtti))))))),
                    NULL))))),
          false, false));
    };
  };
  if (!_currentClassInfo.front()._virtualDerivationsPosition.empty()) {
    shift = 0;
    VirtualInheritancePosition::const_iterator iterEnd =
      _currentClassInfo.front()._virtualDerivationsPosition.end(), iter;
    for (iter = _currentClassInfo.front()._virtualDerivationsPosition.begin();
         iter != iterEnd; ++iter) {
      int previousShift = shift;
      shift = *iter;
      if (shift>previousShift) {
        qualified_name vmtHeaderShiftName = qualified_name_dup(vmtName);
        { std::ostringstream tmp;
          tmp << "_frama_c_vmt_header_for_shift_" << shift;
          free(const_cast<char*>(vmtHeaderShiftName->decl_name));
          vmtHeaderShiftName->decl_name = copy_string(tmp.str());
        };
        globals.insertContainer(
          translation_unit_decl_GlobalVarDecl(
            copy_loc(classLoc),
            decl_or_impl_name_Implementation(vmtHeaderShiftName),
            qual_type_cons(
              NULL,
              typ_Struct(
                qualified_name_cons(NULL, strdup("_frama_c_vmt")),
                tkind_TStandard())),
            opt_some_container(init_expr_Compound_init(
              cons_container(
                init_expr_Single_init(
                  expression_cons(
                    copy_loc(classLoc),
                    exp_node_Binary_operator(
                      BOPLUS, AKRVALUE,
                      expression_cons(
                        copy_loc(classLoc),
                        exp_node_PointerCast(
                          qual_type_cons(
                            NULL,
                            typ_Pointer(
                              pkind_PDataPointer(
                                qual_type_cons(
                                  NULL,
                                  typ_Struct(
                                    qualified_name_cons(
                                      NULL, strdup("_frama_c_vmt_content")),
                                    tkind_TStandard()))))),
                          reference_or_pointer_kind_RPKPointer(),
                          expression_cons(
                            copy_loc(classLoc),
                            exp_node_Variable(
                              variable_Global(qualified_name_dup(vmtName)))))),
                      makeIntLiteral(classLoc,IINT,shift)))),
                cons_container(
                  init_expr_Single_init(
                    makeIntLiteral(
                      classLoc,
                      IINT,
                      _currentClassInfo.front().numberOfMethods()-shift)),
                  cons_container(
                    init_expr_Single_init(
                      expression_cons(
                        copy_loc(classLoc),
                        exp_node_Address(
                          expression_cons(
                            copy_loc(classLoc),
                            exp_node_Variable(
                              variable_Global(
                                qualified_name_dup(nameRtti))))))),
                    NULL))))),
            false, false));
      };
    };

    qualified_name bareVmtHeaderName = qualified_name_dup(vmtHeaderName);
    addBareToQualification(bareVmtHeaderName);
    qualified_name bareNameRtti = qualified_name_dup(nameRtti);
    addBareToQualification(bareNameRtti);
    globals.insertContainer(
      translation_unit_decl_GlobalVarDecl(
        copy_loc(classLoc),
        decl_or_impl_name_Implementation(bareVmtHeaderName),
        qual_type_cons(
          NULL,
          typ_Struct(
            qualified_name_cons(NULL, strdup("_frama_c_vmt")),
            tkind_TStandard())),
        opt_some_container(
          init_expr_Compound_init(
            cons_container(
              init_expr_Single_init(
                expression_cons(
                  copy_loc(classLoc),
                  exp_node_PointerCast(
                    qual_type_cons(
                      NULL,
                      typ_Pointer(
                        pkind_PDataPointer(
                          qual_type_cons(
                            NULL,
                            typ_Struct(
                              qualified_name_cons(
                                NULL, strdup("_frama_c_vmt_content")),
                              tkind_TStandard()))))),
                    reference_or_pointer_kind_RPKPointer(),
                    expression_cons(
                      copy_loc(classLoc),
                      exp_node_Variable(
                        variable_Global(qualified_name_dup(vmtName))))))),
              cons_container(
                init_expr_Single_init(
                  makeIntLiteral(
                    classLoc,
                    IINT,
                    _currentClassInfo.front().numberOfMethods())),
                cons_container(
                  init_expr_Single_init(
                    expression_cons(
                      copy_loc(classLoc),
                      exp_node_Address(
                        expression_cons(
                          copy_loc(classLoc),
                          exp_node_Variable(
                            variable_Global(bareNameRtti)))))),
                  NULL))))),
        false,
        false));
  };
}

void
RTTITable::exitClass(const Clang_utils& utils, ForwardReferenceList& content,
    ForwardReferenceList& globals, location classLoc) {
  assert(!_currentClass.empty());
  if (_currentClassInfo.front().hasVirtualMethods()
       || _currentClassInfo.front().hasVirtualBaseClasses()) {
    const clang::CXXRecordDecl::base_class_const_iterator base
      = _currentClass.front()->bases_begin();
    bool shouldInsertPVMT = _currentClassInfo.front().hasVirtualMethods();
    if (base != _currentClass.front()->bases_end()) {
      const clang::Type* type = base->getType().getTypePtr();
      const clang::CXXRecordDecl* baseClass = type->getAsCXXRecordDecl();
      if (baseClass)
        // If we already have a VMT as first field, just reuse it.
        shouldInsertPVMT &= !hasVirtualMethods(baseClass);
    };
    insertStaticVMTDeclaration(content, classLoc);
    insertStaticBaseClassesDeclaration(content, classLoc);
    insertStaticRTTIDeclaration(content, classLoc);
    insertStaticVMTHeaderDeclaration(content, classLoc);

    if (shouldInsertPVMT)
      content.getFront() = cons_container(
        class_decl_CFieldDecl(
          copy_loc(classLoc),
          strdup("pvmt"),
          qual_type_cons(
            NULL,
            typ_Pointer(
              pkind_PDataPointer(
                qual_type_cons(
                  NULL,
                  typ_Struct(
                    qualified_name_cons(
                      NULL, strdup("_frama_c_vmt")), tkind_TStandard()))))),
          opt_none(),
          false),
        content.getFront());
    std::vector<list*>::const_iterator pvmtInsertionIterEnd
      = _pvmtInsertionPoints.front().end();
    for (std::vector<list*>::const_iterator pvmtInsertionIter
           = _pvmtInsertionPoints.front().begin();
        pvmtInsertionIter != pvmtInsertionIterEnd; ++pvmtInsertionIter)
      addPvmtSetter(utils,_currentClass.front(), **pvmtInsertionIter, classLoc);
    if (!_hasInitRTTIFunctions) {
      insertRttiPrelude(globals, classLoc);
      _hasInitRTTIFunctions = true;
    };

    qualified_name vmtName = insertStaticVMTDefinition(utils, globals,
        classLoc);
    qualified_name nameBaseClasses = insertStaticBaseClassesDefinition(utils,
        globals, classLoc);
    insertDeclStaticVMTHeaderDefinition(globals, classLoc, vmtName);
    qualified_name nameRtti = insertStaticRTTIDefinition(utils, globals,
        classLoc, vmtName, nameBaseClasses);
    insertStaticVMTHeaderDefinition(utils, globals, classLoc, vmtName,
        nameRtti);

    if (!_delayedMethodCalls.empty()) {
      std::map<const clang::CXXRecordDecl*, DelayedMethodCalls>::iterator
        found = _delayedMethodCalls.find(_currentClass.front());
      if (found != _delayedMethodCalls.end()) {
        found->second.updateWith(utils, _currentClassInfo.front());
        _delayedMethodCalls.erase(found);
      };
    };
    std::pair<std::map<const clang::CXXRecordDecl*, ClassInfo>::iterator, bool>
      res = _classInfoTable.insert(std::make_pair(_currentClass.front(),
            ClassInfo()));
    assert(res.second);
    res.first->second.swap(_currentClassInfo.front());
  } else {
      /* class has neither base class nor virtual method. We nevertheless
         generate an empty Rtti structure so that it can be used by future
         classes that inherit from it. There are however two exceptions for
         which we know noone will inherit from the current class:
          - in extern "C" mode, we assume that structs will never 
          belong to the class hierarchy
          - an anonymous class (whose Identifier is NULL) can't be inherited.
      */
    if (!utils.isExternCContext(_currentClass.front())
        && _currentClass.front()->getIdentifier()) {
      insertStaticVMTDeclaration(content, classLoc);
      insertStaticBaseClassesDeclaration(content, classLoc);
      insertStaticRTTIDeclaration(content, classLoc);
      insertStaticVMTHeaderDeclaration(content, classLoc);
      insertStaticEmptyRTTIDefinition(utils, globals, classLoc);
    }
  };
  exitClass();
}

void
RTTITable::retrieveMethodIndex(const Clang_utils& utils,
    const clang::CXXRecordDecl* classCaller, clang::CXXMethodDecl* methodCalled,
    int64_t* methodIndex, /* inheritance */ list* shiftObject,
    /* inheritance */ list* shiftPvmt)
{ std::map<const clang::CXXRecordDecl*, ClassInfo>::const_iterator
    found = _classInfoTable.find(classCaller);
  if (found != _classInfoTable.end()) {
    const ClassInfo& methodTable = found->second;
    const InheritancePath* inheritancePath = NULL;
    const VirtualInheritancePath* virtualInheritancePath = NULL;
    *methodIndex = methodTable.getIndexOfMethod(methodCalled,
        inheritancePath, virtualInheritancePath);
    ForwardReferenceList shiftEnd(*shiftObject);
    if (virtualInheritancePath) {
      tkind templateParameters =
        utils.makeTemplateKind(virtualInheritancePath->first);
      shiftEnd.insertContainer(
        inheritance_cons(
          utils.makeQualifiedName(*virtualInheritancePath->first),
          templateParameters,
          PUBLIC, VVIRTUAL, virtualInheritancePath->second));
    };
    InheritancePath::const_iterator iterEnd = inheritancePath->end();
    for (InheritancePath::const_iterator iter = inheritancePath->begin();
        iter != iterEnd; ++iter) {
      tkind templateParameters = utils.makeTemplateKind(iter->first);
      shiftEnd.insertContainer(
        inheritance_cons(
          utils.makeQualifiedName(*iter->first),
          templateParameters,
          PUBLIC, VSTANDARD, iter->second));
    };
    if (!methodTable.hasPvmtAsFirstField()) {
      shiftEnd = ForwardReferenceList(*shiftPvmt);
      inheritancePath = &methodTable.getPvmtField();
      InheritancePath::const_reverse_iterator iterEnd = inheritancePath->rend(),
          iter = inheritancePath->rbegin();
      for (; iter != iterEnd; ++iter) {
        tkind templateParameters = utils.makeTemplateKind(iter->first);
        shiftEnd.insertContainer(
          inheritance_cons(
            utils.makeQualifiedName(*iter->first), templateParameters,
            PUBLIC, VSTANDARD, iter->second));
      };
    };
  }
  else {
    std::map<const clang::CXXRecordDecl*, DelayedMethodCalls>::iterator
      found = _delayedMethodCalls.find(classCaller);
    if (found == _delayedMethodCalls.end())
      found = _delayedMethodCalls.insert(std::make_pair(classCaller,
        DelayedMethodCalls())).first;
    found->second.addMethodCall(methodCalled, methodIndex, shiftObject,
        shiftPvmt);
  };
}

void
RTTITable::retrieveBaseIndex(const Clang_utils& utils,
    const clang::CXXRecordDecl* classCaller, clang::CXXRecordDecl* baseClass,
    int64_t* accessIndex)
{ std::map<const clang::CXXRecordDecl*, ClassInfo>::const_iterator
    found = _classInfoTable.find(classCaller);
  if (found != _classInfoTable.end()) {
    const ClassInfo& methodTable = found->second;
    bool isVirtual = false;
    *accessIndex = methodTable.getBasePosition(baseClass, isVirtual);
  }
  else {
    std::map<const clang::CXXRecordDecl*, DelayedMethodCalls>::iterator
      found = _delayedMethodCalls.find(classCaller);
    if (found == _delayedMethodCalls.end())
      found = _delayedMethodCalls.insert(std::make_pair(classCaller,
        DelayedMethodCalls())).first;
    found->second.addFieldAccess(baseClass, accessIndex);
  };
}