aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2024-01-22 12:23:20 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2024-01-22 12:23:20 +0200
commit78fb7c04ec8825dba7f83d49c8d04853479bba81 (patch)
tree92ef66846fdf91fac96ee5de54dc8ccdb8b35f76
parent299f76e0fb8621272f983c2f8110185942d3db7e (diff)
Release version 2.5.0-b.25+12.5.0-b.25+1
Backport the following commits from 2.5.0-b.26: - Prevent inner self-typedefs from causing scope cycles. - Skip declarations inside anonymous namespaces. - Support integer template parameters in parser::emit_type_name(). - Make sure configuration report variables are set in skeleton mode. - Make GCC plugin directory, g++ executable name customizable.
-rw-r--r--build/root.build67
-rw-r--r--manifest2
-rw-r--r--odb/buildfile21
-rw-r--r--odb/context.cxx25
-rw-r--r--odb/parser.cxx88
-rw-r--r--odb/processor.cxx22
-rw-r--r--odb/semantics/elements.cxx4
7 files changed, 182 insertions, 47 deletions
diff --git a/build/root.build b/build/root.build
index a07e058..86a02a0 100644
--- a/build/root.build
+++ b/build/root.build
@@ -1,6 +1,20 @@
# file : build/root.build
# license : GNU GPL v3; see accompanying LICENSE file
+# This configuration variable can be used to specify the GCC plugin directory
+# instead of auto-discovering it with -print-file-name=plugin. Primarily
+# useful when dealing with cross-compilation.
+#
+config [dir_path, config.report.variable=plugin_dir] \
+ config.odb.plugin_dir ?= [null]
+
+# This configuration variable can be used to specify the GCC g++ executable
+# name that will be called by the ODB compiler instead of auto-deriving it
+# from config.cxx. Primarily useful when dealing with cross-compilation.
+#
+config [string, config.report.variable=gxx_name] \
+ config.odb.gxx_name ?= [null]
+
config [bool] config.odb.develop ?= false
develop = $config.odb.develop
@@ -36,22 +50,48 @@ if ($build.mode != 'skeleton')
if ($cxx.id != 'gcc')
fail 'ODB compiler can only be built with GCC'
- # Determine the GCC plugin directory.
- #
- # If plugin support is disabled, then -print-file-name will print the name
- # we have passed (the real plugin directory will always be absolute).
+ # Determine the GCC plugin directory unless specified explicitly.
#
+ if ($config.odb.plugin_dir != [null])
+ plugin_dir = $config.odb.plugin_dir
+ else
+ {
+ # If plugin support is disabled, then -print-file-name will print the name
+ # we have passed (the real plugin directory will always be absolute).
+ #
+ plugin_dir = [dir_path] $process.run($cxx.path -print-file-name=plugin)
+
+ if ("$plugin_dir" == plugin)
+ fail "$recall($cxx.path) does not support plugins"
+ }
+
# It can also include '..' components (e.g., on Windows) so normalize it for
# good measure.
#
- plugin_dir = [dir_path] $process.run($cxx.path -print-file-name=plugin)
-
- if ("$plugin_dir" == plugin)
- fail "$recall($cxx.path) does not support plugins"
-
plugin_dir = $normalize($plugin_dir)
- config [config.report] plugin_dir
+ # Determine the g++ executable name unless specified explicitly.
+ #
+ if ($config.odb.gxx_name != [null])
+ gxx_name = $config.odb.gxx_name
+ else
+ {
+ # Unless cross-compiling, pass the C++ compiler's recall path as the g++
+ # name.
+ #
+ # Note that we used to compare complete target triplets but that prooved
+ # too strict. For example, we may be running on x86_64-apple-darwin17.7.0
+ # while the compiler is targeting x86_64-apple-darwin17.3.0.
+ #
+ if ($cxx.target.cpu == $build.host.cpu && \
+ $cxx.target.system == $build.host.system)
+ {
+ gxx_name = $recall($cxx.path)
+ }
+ else
+ fail "g++ executable name must be specified explicitly with \
+config.odb.gxx_name when cross-compiling"
+ }
# Extract the copyright notice from the LICENSE file.
#
@@ -61,3 +101,10 @@ if ($build.mode != 'skeleton')
'Copyright \(c\) (.+)\.', \
'\1')
}
+else
+{
+ # Set for report.
+ #
+ plugin_dir = [null]
+ gxx_name = [null]
+}
diff --git a/manifest b/manifest
index 13c4091..c5e13ed 100644
--- a/manifest
+++ b/manifest
@@ -1,6 +1,6 @@
: 1
name: odb
-version: 2.5.0-b.25
+version: 2.5.0-b.25+1
summary: ODB compiler
license: GPL-3.0-only
topics: C++, ORM, source code generation, object persistence, \
diff --git a/odb/buildfile b/odb/buildfile
index 20f8718..34a6329 100644
--- a/odb/buildfile
+++ b/odb/buildfile
@@ -32,22 +32,6 @@ if ($cxx.target.class != 'windows')
#
plugin{*}: install = bin/
-# Unless cross-compiling, pass the C++ compiler's recall path as the g++
-# name. At some point we should also make it configurable.
-#
-# Note that we used to compare complete target triplets but that prooved too
-# strict. For example, we may be running on x86_64-apple-darwin17.7.0 while
-# the compiler is targeting x86_64-apple-darwin17.3.0.
-#
-if ($cxx.target.cpu == $build.host.cpu && \
- $cxx.target.system == $build.host.system)
-{
- gxx_name = $recall($cxx.path)
- gxx_name = $regex.replace($gxx_name, '\\', '\\\\') # Escape back slashes.
-}
-else
- gxx_name = g++
-
import libs = libcutl%lib{cutl}
import libs += libstudxml%lib{studxml}
@@ -98,7 +82,10 @@ libus{odb}: {hxx ixx txx cxx}{** -odb -options -pregenerated/**} $libs
# Build options.
#
-cxx.poptions += "-I$plugin_dir/include" "-DODB_GXX_NAME=\"$gxx_name\""
+# Note: escape backslashes in gxx_name.
+#
+cxx.poptions += "-I$plugin_dir/include"
+cxx.poptions += "-DODB_GXX_NAME=\"$regex.replace($gxx_name, '\\', '\\\\')\""
cxx.poptions += -DODB_BUILD2 # @@ TMP while supporting other build systems.
## Consumption build ($develop == false).
diff --git a/odb/context.cxx b/odb/context.cxx
index dd4019a..13fc1b3 100644
--- a/odb/context.cxx
+++ b/odb/context.cxx
@@ -1472,7 +1472,7 @@ utype (semantics::data_member& m,
}
}
- if (s->global_scope ())
+ if (!s->named_p () || s->global_scope ())
break;
}
@@ -1882,8 +1882,13 @@ schema (semantics::scope& s) const
namespace_* ns (dynamic_cast<namespace_*> (ps));
- if (ns == 0)
- continue; // Some other scope.
+ if (ns == 0) // Some other scope.
+ {
+ if (!ps->named_p ())
+ break;
+
+ continue;
+ }
if (ns->extension ())
ns = &ns->original ();
@@ -1920,7 +1925,8 @@ schema (semantics::scope& s) const
n.swap (r);
}
- if (r.fully_qualified () || ns->global_scope ())
+ if (r.fully_qualified () ||
+ ns->global_scope ()) // Note: namespaces always named.
break;
}
@@ -1952,8 +1958,13 @@ table_name_prefix (semantics::scope& s) const
namespace_* ns (dynamic_cast<namespace_*> (ps));
- if (ns == 0)
- continue; // Some other scope.
+ if (ns == 0) // Some other scope.
+ {
+ if (!ps->named_p ())
+ break;
+
+ continue;
+ }
if (ns->extension ())
ns = &ns->original ();
@@ -1964,7 +1975,7 @@ table_name_prefix (semantics::scope& s) const
r = n.uname () + r;
}
- if (ns->global_scope ())
+ if (ns->global_scope ()) // Note: namespaces always named.
break;
}
diff --git a/odb/parser.cxx b/odb/parser.cxx
index 58388c9..c026808 100644
--- a/odb/parser.cxx
+++ b/odb/parser.cxx
@@ -176,6 +176,7 @@ private:
unit* unit_;
scope* scope_;
+ vector<scope*> class_scopes_; // Current hierarchy of class-like scopes.
size_t error_;
decl_set decls_;
@@ -263,6 +264,11 @@ emit_class (tree c, path const& file, size_t line, size_t clmn, bool stub)
if (stub || !COMPLETE_TYPE_P (c))
return *c_node;
+ // Note: "include" the base classes into the class scope (see comment for
+ // self-typedefs in emit_type_decl()).
+ //
+ class_scopes_.push_back (c_node);
+
// Traverse base information.
//
tree bis (TYPE_BINFO (c));
@@ -557,6 +563,8 @@ emit_class (tree c, path const& file, size_t line, size_t clmn, bool stub)
diagnose_unassoc_pragmas (decls);
scope_ = prev_scope;
+ class_scopes_.pop_back ();
+
return *c_node;
}
@@ -583,6 +591,8 @@ emit_union (tree u, path const& file, size_t line, size_t clmn, bool stub)
if (stub || !COMPLETE_TYPE_P (u))
return *u_node;
+ class_scopes_.push_back (u_node);
+
// Collect member declarations so that we can traverse them in
// the source code order.
//
@@ -728,6 +738,7 @@ emit_union (tree u, path const& file, size_t line, size_t clmn, bool stub)
diagnose_unassoc_pragmas (decls);
scope_ = prev_scope;
+ class_scopes_.pop_back ();
return *u_node;
}
@@ -942,9 +953,10 @@ collect (tree ns)
if (!DECL_IS_BUILTIN (decl) || DECL_NAMESPACE_STD_P (decl))
{
+ tree dn (DECL_NAME (decl));
+
if (trace)
{
- tree dn (DECL_NAME (decl));
char const* name (dn ? IDENTIFIER_POINTER (dn) : "<anonymous>");
ts << "namespace " << name << " at "
@@ -952,7 +964,12 @@ collect (tree ns)
<< DECL_SOURCE_LINE (decl) << endl;
}
- collect (decl);
+ // Skip anonymous namespaces (there could be nothing of interest to us
+ // inside but they wreck havoc with our attempts to sort declarations
+ // into namespaces).
+ //
+ if (dn != 0)
+ collect (decl);
}
}
}
@@ -1079,6 +1096,8 @@ emit ()
break;
}
}
+
+ assert (class_scopes_.empty ());
}
// Diagnose any position pragmas that haven't been associated.
@@ -1201,6 +1220,58 @@ emit_type_decl (tree decl)
size_t c (DECL_SOURCE_COLUMN (decl));
type& node (emit_type (t, decl_access (decl), f, l, c));
+
+ // Omit inner self-typedefs (e.g., a class typedefs itself in its own
+ // scope). Such aliases don't buy us anything (in particular, they cannot
+ // be used to form an fq-name) but they do cause scoping cycles if this
+ // name happens to be used to find outer scope (see scope::scope_()).
+ // Note that this means we can now have class template instantiations that
+ // are not named and therefore don't belong to any scope.
+ //
+ // Note that emit_type() might still enter this decl as a hint. It's fuzzy
+ // whether this is harmless or not.
+ //
+ // Note also that using the normal scope hierarchy does not work in more
+ // complex cases where templates cross-self-typedef. So instead we now use
+ // a special-purpose mechanism (class_scopes_). Note for this to work
+ // correctly (hopefully), the class should be "in scope" for its bases.
+ // Here is a representative examples (inspired by code in Eigen):
+ //
+ // template <typename M>
+ // struct PlainObjectBase
+ // {
+ // typedef M Self;
+ // };
+ //
+ // template <typename T, int X, int Y>
+ // struct Matrix: PlainObjectBase<Matrix<T, X, Y>>
+ // {
+ // typedef PlainObjectBase<Matrix> Base;
+ // typedef Matrix Self;
+ // };
+ //
+ // typedef Matrix<double, 3, 1> Vector3d;
+ //
+ // Here we want both Self's (but not Base) to be skipped.
+ //
+ if (scope* s = dynamic_cast<scope*> (&node))
+ {
+ for (auto i (class_scopes_.rbegin ()); i != class_scopes_.rend (); ++i)
+ {
+ if (s == *i)
+ {
+ if (trace)
+ {
+ string s (emit_type_name (t, false));
+
+ ts << "omitting inner self-typedef " << s << " (" << &node
+ << ") -> " << name << " at " << f << ":" << l << endl;
+ }
+ return 0;
+ }
+ }
+ }
+
typedefs& edge (unit_->new_edge<typedefs> (*scope_, node, name));
// Find our hint.
@@ -1327,6 +1398,8 @@ emit_class_template (tree t, bool stub)
if (stub || !COMPLETE_TYPE_P (c))
return *ct_node;
+ class_scopes_.push_back (ct_node);
+
// Collect member declarations so that we can traverse them in
// the source code order. For now we are only interested in
// nested class template declarations.
@@ -1382,6 +1455,7 @@ emit_class_template (tree t, bool stub)
diagnose_unassoc_pragmas (decls);
scope_ = prev_scope;
+ class_scopes_.pop_back ();
return *ct_node;
}
@@ -1410,6 +1484,8 @@ emit_union_template (tree t, bool stub)
if (stub || !COMPLETE_TYPE_P (u))
return *ut_node;
+ class_scopes_.push_back (ut_node);
+
// Collect member declarations so that we can traverse them in
// the source code order. For now we are only interested in
// nested class template declarations.
@@ -1465,6 +1541,7 @@ emit_union_template (tree t, bool stub)
diagnose_unassoc_pragmas (decls);
scope_ = prev_scope;
+ class_scopes_.pop_back ();
return *ut_node;
}
@@ -2053,9 +2130,12 @@ emit_type_name (tree type, bool direct)
if (i != 0)
id += ", ";
- // Assume type-only arguments.
+ // Assume integer and type-only arguments.
//
- id += emit_type_name (a);
+ if (TREE_CODE (a) == INTEGER_CST)
+ id += to_string (integer_value (a));
+ else
+ id += emit_type_name (a);
}
id += '>';
diff --git a/odb/processor.cxx b/odb/processor.cxx
index 9cda5e6..d48baa7 100644
--- a/odb/processor.cxx
+++ b/odb/processor.cxx
@@ -2194,8 +2194,13 @@ namespace
namespace_* ns (dynamic_cast<namespace_*> (s));
- if (ns == 0)
- continue; // Some other scope.
+ if (ns == 0) // Some other scope.
+ {
+ if (!s->named_p ())
+ break;
+
+ continue;
+ }
if (ns->extension ())
ns = &ns->original ();
@@ -2207,7 +2212,7 @@ namespace
break;
}
- if (ns->global_scope ())
+ if (ns->global_scope ()) // Note: namespaces always named.
break;
}
@@ -2702,15 +2707,20 @@ namespace
namespace_* ns (dynamic_cast<namespace_*> (s));
- if (ns == 0)
- continue; // Some other scope.
+ if (ns == 0) // Some other scope.
+ {
+ if (!s->named_p ())
+ break;
+
+ continue;
+ }
if (ns->extension ())
ns = &ns->original ();
if (!ns->count ("pointer"))
{
- if (ns->global_scope ())
+ if (ns->global_scope ()) // Note: namespace always named.
break;
else
continue;
diff --git a/odb/semantics/elements.cxx b/odb/semantics/elements.cxx
index fba9b9b..b5793d0 100644
--- a/odb/semantics/elements.cxx
+++ b/odb/semantics/elements.cxx
@@ -56,7 +56,7 @@ namespace semantics
if (p == &s)
return true;
- if (p->global_scope ())
+ if (!p->named_p () || p->global_scope ())
break;
}
@@ -476,7 +476,7 @@ namespace semantics
// Look in the outer scope unless requested not to or if this is
// the global scope.
//
- if ((flags & exclude_outer) == 0 && !global_scope ())
+ if ((flags & exclude_outer) == 0 && named_p () && !global_scope ())
return scope ().lookup (name, ti, flags, hidden);
return 0;