Fix several ICG class template bugs (#1871)

* Fix several bugs with processing templates in ICG

- Fixed an issue where io_src code for some templates was being placed in the
  wrong file.
- Fixed an issue with templates being instantiated with templates as parameters.
- Fixed an issue with templates that instantiate templates.

Added additional tests to cover these cases.

* Moved the list of template argument header dependencies from ClassValues to PrintFileContents10 so they can be printed to the io_ file regardless of the order in which class info is printed.

* Moved the list of template argument header dependencies from ClassValues to PrintFileContents10 so they can be printed to the io_ file regardless of the order in which class info is printed.

Moved the list of template argument header dependencies from ClassValues to PrintFileContents10 so they can be printed to the io_ file regardless of the order in which class info is printed.

* Added support to handle template enum class type argument and removed some commented code.

Added support to handle template enum class type argument and removed some commented code.

---------

Co-authored-by: Hong Chen <hchen99@users.noreply.github.com>
This commit is contained in:
ninotarantino
2025-04-29 15:30:49 -05:00
committed by GitHub
parent 0312ca6fe8
commit 91a348d7e0
16 changed files with 269 additions and 62 deletions

View File

@ -3,11 +3,20 @@ import math
from trick.unit_test import *
def main():
tso.tobj.TTT_var.aa = 1000
tso.tobj.TTT_var.bb = 2000
tso.tobj.TTT_var_scalar_builtins.aa = 1000
tso.tobj.TTT_var_scalar_builtins.bb = 2000
print ("tso.tobj.TTT_var_scalar_builtins.aa =" , tso.tobj.TTT_var_scalar_builtins.aa)
print ("tso.tobj.TTT_var_scalar_builtins.bb =" , tso.tobj.TTT_var_scalar_builtins.bb)
print ("tso.tobj.TTT_var.aa =") , tso.tobj.TTT_var.aa
print ("tso.tobj.TTT_var.bb =") , tso.tobj.TTT_var.bb
tso.tobj.TTT_var_array_builtins.aa = [1, 2]
tso.tobj.TTT_var_array_builtins.bb = [1.1234, 2.5678, -3.9]
print ("tso.tobj.TTT_var_array_builtins.aa =" , tso.tobj.TTT_var_array_builtins.aa)
print ("tso.tobj.TTT_var_array_builtins.bb =" , tso.tobj.TTT_var_array_builtins.bb)
tso.tobj.TTT_var_enum.aa = trick.Bar_1
tso.tobj.TTT_var_enum.bb = [trick.Bar_1, trick.Bar_2]
print ("tso.tobj.TTT_var_enum.aa =" , tso.tobj.TTT_var_enum.aa)
print ("tso.tobj.TTT_var_enum.bb =" , tso.tobj.TTT_var_enum.bb)
trick.checkpoint_end(True)

View File

@ -1,17 +1,25 @@
#include "sim_objects/default_trick_sys.sm"
##include "trick/SimObject.hh"
##include "TemplateTest.hh"
##include "Potato.hh"
##include "Onion.hh"
##include "Foo.hh"
##include "FooA.hh"
class templateSimObject : public Trick::SimObject {
public:
TemplateTest tobj ;
potato::Potato<onion::Onion> potato;
FooA<MyEnumClass::Enum> FooA_enum;
templateSimObject() {
(1.0, "scheduled") trick_ret = print() ;
(1.0, "scheduled") trick_ret = printMe() ;
}
int print() { std::cout << "In print()" << std::endl ; return 0 ; } ;
int printMe() { std::cout << "In printMe()" << std::endl ; return 0 ; } ;
} ;

View File

@ -1,4 +1,4 @@
TRICK_CFLAGS += -I.
TRICK_CXXFLAGS += -I.
TRICK_CFLAGS += -I./models
TRICK_CXXFLAGS += -I./models

View File

@ -1,48 +0,0 @@
/**
@file
@verbatim
PURPOSE:
(Template tests)
@endverbatim
*******************************************************************************/
#ifndef TEMPLATETEST_HH
#define TEMPLATETEST_HH
template <class A, class B>
class TTT {
public:
TTT() {
aa = 0 ;
bb = 0 ;
cc = NULL ;
dd = NULL ;
} ;
A aa ;
B bb ;
TTT<A,B> * ttt ;
typedef TTT<A,B> C ;
C * cc ;
typedef TTT<B,A> D ;
D * dd ;
} ;
class TemplateTest {
friend class InputProcessor ;
friend void init_attrTemplateTest() ;
public:
TTT< int , double > TTT_var ;
};
#ifdef SWIG
%struct_str(TemplateTest)
#endif
#endif /* _BALL_HH_ */

View File

@ -0,0 +1,30 @@
/**
@file
@verbatim
PURPOSE:
(Template tests)
@endverbatim
*******************************************************************************/
#ifndef FOO_HH
#define FOO_HH
class MyEnumClass {
public:
enum class Enum {};
class Inner {};
};
template <class T>
class Foo {
public:
T t; /* (--) */
};
enum Bar {
Bar_1,
Bar_2
};
#endif /* FOO_HH */

View File

@ -0,0 +1,15 @@
/**
@file
@verbatim
PURPOSE:
(Template tests)
@endverbatim
*******************************************************************************/
#ifndef FOOA_HH
#define FOOA_HH
template <class T> class FooA {};
#endif /* FOOA_HH */

View File

@ -0,0 +1,17 @@
/**
@file
@verbatim
PURPOSE:
(Template tests)
@endverbatim
*******************************************************************************/
#ifndef ONION_HH
#define ONION_HH
namespace onion {
class Onion {};
}
#endif /* ONION_HH */

View File

@ -0,0 +1,22 @@
/**
@file
@verbatim
PURPOSE:
(Template tests)
@endverbatim
*******************************************************************************/
#ifndef POTATO_HH
#define POTATO_HH
namespace potato {
template <class T>
class Potato {
public:
class Inner {};
Inner inner;
};
}
#endif /* POTATO_HH */

View File

@ -0,0 +1,54 @@
/**
@file
@verbatim
PURPOSE:
(Template tests)
@endverbatim
*******************************************************************************/
#ifndef TEMPLATETEST_HH
#define TEMPLATETEST_HH
#include "Foo.hh"
template <class A, class B>
class TTT1 {
public:
A aa ;
B bb ;
TTT1<A,B> * ttt ; /* ** */
typedef TTT1<A,B> C ;
C * cc ; /* ** */
typedef TTT1<B,A> D ;
D * dd ; /* ** */
} ;
template <class T>
class TTT2 {
public:
TTT1<T, int> a;
Foo<T[3]> b;
};
class TemplateTest {
friend class InputProcessor ;
friend void init_attrTemplateTest() ;
public:
TTT1< int , double > TTT_var_scalar_builtins ;
TTT1< int[2] , double[3] > TTT_var_array_builtins ;
TTT1< Bar, Bar[2] > TTT_var_enum ;
TTT1< Foo<int>, Foo<double[2]>[3] > TTT_var_template_parameters ;
TTT2< Foo< TTT1< int, TTT2<char> > > > TTT_templates_of_templates ;
};
#ifdef SWIG
%struct_str(TemplateTest)
#endif
#endif /* _BALL_HH_ */

View File

@ -2,6 +2,7 @@
#include <iostream>
#include <sstream>
#include <stack>
#include <string>
#include "llvm/Support/CommandLine.h"
#include "clang/Basic/SourceManager.h"
@ -16,6 +17,7 @@
#include "Utilities.hh"
#include "CommentSaver.hh"
#include "PrintAttributes.hh"
#include "PrintFileContents10.hh"
#include "BraceMacro.hh"
extern llvm::cl::opt< int > debug_level ;
@ -229,7 +231,7 @@ bool CXXRecordVisitor::VisitCXXRecordDecl( clang::CXXRecordDecl *rec ) {
cval.setPOD(rec->isPOD()) ;
cval.setSize(rec->getASTContext().getASTRecordLayout(rec).getSize().getQuantity()) ;
addTemplateArgumentDependencies(rec);
//std::cout << "parsing " << cval.getName() << std::endl ;
//std::cout << " processing inheritance " << rec->getNumBases() << " " << rec->getNumVBases() << "" << std::endl ;
@ -419,3 +421,55 @@ bool CXXRecordVisitor::isPrivateEmbeddedClass( std::string in_name ) {
}
return false ;
}
void CXXRecordVisitor::addTemplateArgumentDependencies(const clang::CXXRecordDecl *rec) {
if (cval.getFileName() == "S_source.hh" ||
!clang::ClassTemplateSpecializationDecl::classof(rec)) {
return;
}
const auto * ctd = clang::cast<clang::ClassTemplateSpecializationDecl>(rec);
// Iterate over all template arguments. If any of these arguments come from an
// external header file, make sure to #include it when generating this class's
// io_src file.
for (const auto & arg : ctd->getTemplateArgs().asArray()) {
if (arg.getKind() != clang::TemplateArgument::ArgKind::Type ||
!arg.getAsType().getTypePtrOrNull()) {
continue;
}
const auto * type_ptr = arg.getAsType().getTypePtr();
clang::TagDecl * arg_decl = nullptr;
switch (type_ptr->getTypeClass()) {
case clang::Type::Record:
arg_decl = type_ptr->getAsCXXRecordDecl();
break;
case clang::Type::Enum: {
// Handle enum or enum class
const clang::EnumType *et = type_ptr->getAs<clang::EnumType>();
if (et) {
arg_decl = et->getDecl();
}
break;
}
case clang::Type::ConstantArray:
// Will remain nullptr if this is a builtin type.
arg_decl = type_ptr->getPointeeOrArrayElementType()->getAsCXXRecordDecl();
break;
default:
break;
}
if (!arg_decl) {
continue;
}
std::string arg_header_file = getFileName(ci, arg_decl->getBraceRange().getEnd(), hsd);
pa.printer->addTemplateArgumentHeaderDependency(cval.getFileName(), arg_header_file);
if (debug_level >= 2) {
std::cout << "\n\033[34mCXXRecordVisitor addTemplateArgumentDependencies "
<< arg_header_file << "\033[0m" << std::endl ;
}
}
}

View File

@ -58,6 +58,9 @@ class CXXRecordVisitor : public clang::RecursiveASTVisitor<CXXRecordVisitor> {
static void addPrivateEmbeddedClass(std::string in_name) ;
static bool isPrivateEmbeddedClass(std::string in_name) ;
private:
/* Save any additional #includes required by template arguments */
void addTemplateArgumentDependencies(const clang::CXXRecordDecl *rec) ;
/** The compiler instance. */
clang::CompilerInstance & ci ;

View File

@ -290,9 +290,9 @@ bool FieldVisitor::ProcessTemplate(std::string in_name , clang::CXXRecordDecl *
template_spec_cvis.get_class_data()->setMangledTypeName(processed_templates[in_name]) ;
template_spec_cvis.TraverseCXXRecordDecl(crd) ;
// Set the actual type name and file name. Print the attributes for this template type
// Set the actual type name. Print the attributes for this template type
template_spec_cvis.get_class_data()->setName(in_name) ;
template_spec_cvis.get_class_data()->setFileName(fdes->getFileName()) ;
//template_spec_cvis.get_class_data()->setFileName(fdes->getFileName()) ;
pa.printClass(template_spec_cvis.get_class_data()) ;
if ( debug_level >= 4 ) {

View File

@ -67,6 +67,9 @@ class PrintAttributes {
bool isHeaderExcluded(const std::string& header, bool exclude_ext_libs = true);
void markHeaderAsVisited(const std::string& header);
/** Version specific attributes printer */
PrintFileContentsBase * printer ;
protected:
const bool verboseBuild = (getenv("TRICK_VERBOSE_BUILD") || getenv("VERBOSE"));
@ -93,9 +96,6 @@ class PrintAttributes {
/** Compiler instance */
clang::CompilerInstance & ci ;
/** Version specific attributes printer */
PrintFileContentsBase * printer ;
/** Force all io_src files to be written */
bool force ;

View File

@ -347,6 +347,8 @@ void PrintFileContents10::print_stl_helper(std::ostream & ostream , ClassValues
}
void PrintFileContents10::printClass( std::ostream & ostream , ClassValues * cv ) {
//print_template_argument_header_deps(ostream, cv) ;
print_template_argument_header_dependencies(ostream, cv->getFileName()) ;
print_class_attr(ostream, cv) ;
print_stl_helper(ostream, cv) ;
print_init_attr_func(ostream, cv) ;
@ -416,3 +418,22 @@ void PrintFileContents10::printStlFunction(const std::string& name, const std::s
<< " " << call << ";" << std::endl
<< "}" << std::endl ;
}
void PrintFileContents10::addTemplateArgumentHeaderDependency(const std::string& header, const std::string& dependency) {
if (!dependency.empty()) {
HeaderInfo header_dependency(dependency);
template_argument_header_dependencies[header].insert(header_dependency);
}
}
void PrintFileContents10::print_template_argument_header_dependencies(std::ostream & outfile, std::string header_file_name) {
auto it = template_argument_header_dependencies.find(header_file_name);
if (it != template_argument_header_dependencies.end()) {
for (const auto& headerInfo : it->second) {
if (!headerInfo.printed && headerInfo.header_path != header_file_name) {
outfile << "#include \"" << headerInfo.header_path << "\"\n";
const_cast<HeaderInfo&>(headerInfo).printed = true;
}
}
}
}

View File

@ -47,6 +47,9 @@ class PrintFileContents10 : public PrintFileContentsBase {
virtual void printEnumMap(std::ostream & out, EnumValues * ev) ;
virtual void printEnumMapFooter(std::ostream & out) ;
/** stores template argument header dependencies to be printed */
virtual void addTemplateArgumentHeaderDependency(const std::string& header, const std::string& dependency);
private:
/** Prints enumeration attributes */
@ -102,6 +105,22 @@ class PrintFileContents10 : public PrintFileContentsBase {
void print_clear_stl(std::ostream & outfile , FieldDescription * fdes , ClassValues * in_class) ;
void printStlFunction(const std::string& name, const std::string& parameters, const std::string& call, std::ostream& ostream, FieldDescription& fieldDescription, ClassValues& classValues);
/** Prints #include statements requried by tempalte arguments for the specified header */
void print_template_argument_header_dependencies(std::ostream & outfile, std::string header_file_name) ;
/** Struct contains the header path and whether it's printed already */
struct HeaderInfo {
std::string header_path;
bool printed;
HeaderInfo(const std::string& path) : header_path(path), printed(false) {}
// comparison operator for std::set
bool operator<(const HeaderInfo& other) const {
return header_path < other.header_path;
}
};
/** The key is the header that have template argument header dependencies */
std::map<std::string, std::set<HeaderInfo>> template_argument_header_dependencies;
} ;
#endif

View File

@ -45,6 +45,9 @@ class PrintFileContentsBase {
/* gets a vector of fields that can be printed */
std::vector<FieldDescription*> getPrintableFields(ClassValues& classValues, unsigned int ioMask = 0xFFFFFFF);
/** stores template argument header dependencies to be printed */
virtual void addTemplateArgumentHeaderDependency(const std::string& header, const std::string& dependency) = 0;
protected:
/** Prints the io_src_allocate function */
virtual void print_units_map(std::ostream & ostream, ClassValues * cv) ;