diff --git a/src/Type.h b/src/Type.h index f8c9e385f7..e7dc3c52a2 100644 --- a/src/Type.h +++ b/src/Type.h @@ -618,11 +618,16 @@ public: const detail::AttrPtr& GetAttr(detail::AttrTag a) const { return attrs ? attrs->Find(a) : detail::Attr::nil; } + const detail::Location* GetLocationInfo() const { return &loc; } + void DescribeReST(ODesc* d, bool roles_only = false) const; TypePtr type; detail::AttributesPtr attrs; const char* id = nullptr; + +private: + detail::Location loc = detail::GetCurrentLocation(); }; using type_decl_list = PList; diff --git a/src/script_opt/CPP/InitsInfo.cc b/src/script_opt/CPP/InitsInfo.cc index b9a5551cd9..122b37b9b2 100644 --- a/src/script_opt/CPP/InitsInfo.cc +++ b/src/script_opt/CPP/InitsInfo.cc @@ -544,7 +544,8 @@ void FuncTypeInfo::AddInitializerVals(std::vector& ivs) const { ivs.emplace_back(Fmt(static_cast(expressionless_return_okay))); } -RecordTypeInfo::RecordTypeInfo(CPPCompile* _c, TypePtr _t) : AbstractTypeInfo(_c, std::move(_t)) { +RecordTypeInfo::RecordTypeInfo(CPPCompile* _c, TypePtr _t, int _addl_fields) + : AbstractTypeInfo(_c, std::move(_t)), addl_fields(_addl_fields) { // Note, we leave init_cohort at 0 because the skeleton of this type // is built in the first cohort. auto r = t->AsRecordType()->Types(); @@ -574,6 +575,7 @@ RecordTypeInfo::RecordTypeInfo(CPPCompile* _c, TypePtr _t) : AbstractTypeInfo(_c void RecordTypeInfo::AddInitializerVals(std::vector& ivs) const { ivs.emplace_back(Fmt(c->TrackString(t->GetName()))); + ivs.emplace_back(Fmt(addl_fields)); auto n = field_names.size(); diff --git a/src/script_opt/CPP/InitsInfo.h b/src/script_opt/CPP/InitsInfo.h index f900b8273c..b7e58b63d1 100644 --- a/src/script_opt/CPP/InitsInfo.h +++ b/src/script_opt/CPP/InitsInfo.h @@ -644,11 +644,15 @@ private: class RecordTypeInfo : public AbstractTypeInfo { public: - RecordTypeInfo(CPPCompile* c, TypePtr _t); + RecordTypeInfo(CPPCompile* c, TypePtr _t, int _addl_fields); void AddInitializerVals(std::vector& ivs) const override; private: + // If non-zero, where additional fields begin. Only used for standalone + // compilation. + int addl_fields; + std::vector field_names; std::vector field_types; std::vector field_attrs; diff --git a/src/script_opt/CPP/RuntimeInits.cc b/src/script_opt/CPP/RuntimeInits.cc index 37249be638..b7f28a7403 100644 --- a/src/script_opt/CPP/RuntimeInits.cc +++ b/src/script_opt/CPP/RuntimeInits.cc @@ -383,11 +383,18 @@ TypePtr CPP_TypeInits::BuildRecordType(InitsManager* im, ValElemVec& init_vals, auto r = cast_intrusive(inits_vec[offset]); ASSERT(r); - if ( r->NumFields() == 0 ) { + auto addl_fields = init_vals[2]; + + if ( addl_fields > 0 || r->NumFields() == 0 ) { + // We shouldn't be adding fields if the record doesn't have any + // existing fields - that would reflect an initialization botch. + if ( addl_fields > 0 && r->NumFields() == 0 ) + reporter->InternalError("record unexpectedly empty when adding fields"); + type_decl_list tl; auto n = init_vals.size(); - auto i = 2U; + auto i = 3U + addl_fields * 3; while ( i < n ) { auto s = im->Strings(init_vals[i++]); diff --git a/src/script_opt/CPP/Types.cc b/src/script_opt/CPP/Types.cc index 37215c0d62..42f4c7ec82 100644 --- a/src/script_opt/CPP/Types.cc +++ b/src/script_opt/CPP/Types.cc @@ -189,9 +189,43 @@ shared_ptr CPPCompile::RegisterType(const TypePtr& tp) { processed_types[t] = nullptr; + // When doing standalone compilation, if the type is a record *and* + // (1) it's not one that we're fully generating (i.e., it's not solely + // defined in the scripts that we're compiling-to-standalone), and (2) the + // scripts we're compiling extend the record using "redef += record ...", + // then we need to track the offset where those record extensions start, + // so that when initializing the standalone code, we can add in those + // record fields. + // + // If any of those conditions don't hold, then this variable will remain 0. + int addl_fields = 0; + + bool type_init_needed = standalone && obj_matches_opt_files(tp); + + if ( standalone && ! type_init_needed ) { + if ( tp->Tag() == TYPE_RECORD ) { + auto tr = tp->AsRecordType(); + for ( auto i = tr->NumOrigFields(); i < tr->NumFields(); ++i ) { + auto fd = tr->FieldDecl(i); + if ( filename_matches_opt_files(fd->GetLocationInfo()->filename) ) { + if ( addl_fields == 0 ) + addl_fields = i; + } + else if ( addl_fields > 0 ) + reporter->FatalError( + "can't compile standalone-C++ with field \"%s\" in record \"%s\" added after those introduced " + "by compiled script", + fd->id, t->GetName().c_str()); + } + + if ( addl_fields > 0 ) + type_init_needed = true; + } + } + shared_ptr gi; - if ( (standalone && obj_matches_opt_files(tp)) || t->GetName().empty() ) { + if ( type_init_needed || t->GetName().empty() ) { switch ( t->Tag() ) { case TYPE_ADDR: case TYPE_ANY: @@ -221,7 +255,7 @@ shared_ptr CPPCompile::RegisterType(const TypePtr& tp) { case TYPE_TABLE: gi = make_shared(this, tp); break; - case TYPE_RECORD: gi = make_shared(this, tp); break; + case TYPE_RECORD: gi = make_shared(this, tp, addl_fields); break; case TYPE_FUNC: gi = make_shared(this, tp); break; diff --git a/src/script_opt/ScriptOpt.cc b/src/script_opt/ScriptOpt.cc index 2175570085..f160d1e963 100644 --- a/src/script_opt/ScriptOpt.cc +++ b/src/script_opt/ScriptOpt.cc @@ -125,13 +125,13 @@ bool should_analyze(const ScriptFuncPtr& f, const StmtPtr& body) { return false; } -bool obj_matches_opt_files(const Obj* obj) { +bool filename_matches_opt_files(const char* filename) { auto& ofiles = analysis_options.only_files; if ( ofiles.empty() ) return false; - auto fin = util::detail::normalize_path(obj->GetLocationInfo()->filename); + auto fin = util::detail::normalize_path(filename); for ( auto& o : ofiles ) if ( std::regex_match(fin, o) ) @@ -140,6 +140,8 @@ bool obj_matches_opt_files(const Obj* obj) { return false; } +bool obj_matches_opt_files(const Obj* obj) { return filename_matches_opt_files(obj->GetLocationInfo()->filename); } + static bool optimize_AST(ScriptFuncPtr f, std::shared_ptr& pf, std::shared_ptr& rc, ScopePtr scope, StmtPtr& body) { pf = std::make_shared(f.get(), body, true); diff --git a/src/script_opt/ScriptOpt.h b/src/script_opt/ScriptOpt.h index 028a93ea54..f36888272e 100644 --- a/src/script_opt/ScriptOpt.h +++ b/src/script_opt/ScriptOpt.h @@ -254,8 +254,9 @@ extern void add_file_analysis_pattern(AnalyOpt& opts, const char* pat); // it should be skipped. extern bool should_analyze(const ScriptFuncPtr& f, const StmtPtr& body); -// True if the given object's location matches one specified by +// True if the given filename or object location matches one specified by // --optimize-files=... +extern bool filename_matches_opt_files(const char* filename); extern bool obj_matches_opt_files(const Obj* obj); inline bool obj_matches_opt_files(const ObjPtr& obj) { return obj_matches_opt_files(obj.get()); }