Module Name:    src
Committed By:   joerg
Date:           Sun May 30 00:12:31 UTC 2021

Modified Files:
        src/external/bsd/libc++/dist/libcxxrt/src: exception.cc
            libelftc_dem_gnu3.c unwind-itanium.h

Log Message:
Merge 47661d00cd4d6cd728ae31b0bb29a49a6c06272a


To generate a diff of this commit:
cvs rdiff -u -r1.2 -r1.3 \
    src/external/bsd/libc++/dist/libcxxrt/src/exception.cc \
    src/external/bsd/libc++/dist/libcxxrt/src/libelftc_dem_gnu3.c \
    src/external/bsd/libc++/dist/libcxxrt/src/unwind-itanium.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/external/bsd/libc++/dist/libcxxrt/src/exception.cc
diff -u src/external/bsd/libc++/dist/libcxxrt/src/exception.cc:1.2 src/external/bsd/libc++/dist/libcxxrt/src/exception.cc:1.3
--- src/external/bsd/libc++/dist/libcxxrt/src/exception.cc:1.2	Fri Jun 26 00:50:39 2015
+++ src/external/bsd/libc++/dist/libcxxrt/src/exception.cc	Sun May 30 00:12:31 2021
@@ -304,13 +304,17 @@ static pthread_key_t eh_key;
 static void exception_cleanup(_Unwind_Reason_Code reason, 
                               struct _Unwind_Exception *ex)
 {
-	__cxa_free_exception(static_cast<void*>(ex));
+	// Exception layout:
+	// [__cxa_exception [_Unwind_Exception]] [exception object]
+	//
+	// __cxa_free_exception expects a pointer to the exception object
+	__cxa_free_exception(static_cast<void*>(ex + 1));
 }
 static void dependent_exception_cleanup(_Unwind_Reason_Code reason, 
                               struct _Unwind_Exception *ex)
 {
 
-	__cxa_free_dependent_exception(static_cast<void*>(ex));
+	__cxa_free_dependent_exception(static_cast<void*>(ex + 1));
 }
 
 /**
@@ -340,7 +344,8 @@ static void thread_cleanup(void* thread_
 		if (info->foreign_exception_state != __cxa_thread_info::none)
 		{
 			_Unwind_Exception *e = reinterpret_cast<_Unwind_Exception*>(info->globals.caughtExceptions);
-			e->exception_cleanup(_URC_FOREIGN_EXCEPTION_CAUGHT, e);
+			if (e->exception_cleanup)
+				e->exception_cleanup(_URC_FOREIGN_EXCEPTION_CAUGHT, e);
 		}
 		else
 		{
@@ -516,7 +521,7 @@ static void emergency_malloc_free(char *
 			break;
 		}
 	}
-	assert(buffer > 0 &&
+	assert(buffer >= 0 &&
 	       "Trying to free something that is not an emergency buffer!");
 	// emergency_malloc() is expected to return 0-initialized data.  We don't
 	// zero the buffer when allocating it, because the static buffers will
@@ -556,7 +561,7 @@ static void free_exception(char *e)
 {
 	// If this allocation is within the address range of the emergency buffer,
 	// don't call free() because it was not allocated with malloc()
-	if ((e > emergency_buffer) &&
+	if ((e >= emergency_buffer) &&
 	    (e < (emergency_buffer + sizeof(emergency_buffer))))
 	{
 		emergency_malloc_free(e);
@@ -854,6 +859,13 @@ extern "C" void __cxa_rethrow()
 
 	assert(ex->handlerCount > 0 && "Rethrowing uncaught exception!");
 
+	// `globals->uncaughtExceptions` was decremented by `__cxa_begin_catch`.
+	// It's normally incremented by `throw_exception`, but this path invokes
+	// `_Unwind_Resume_or_Rethrow` directly to rethrow the exception.
+	// This path is only reachable if we're rethrowing a C++ exception -
+	// foreign exceptions don't adjust any of this state.
+	globals->uncaughtExceptions++;
+
 	// ex->handlerCount will be decremented in __cxa_end_catch in enclosing
 	// catch block
 	
@@ -1199,11 +1211,13 @@ extern "C" void *__cxa_begin_catch(void 
 	// we see is a foreign exception then we won't have called it yet.
 	__cxa_thread_info *ti = thread_info();
 	__cxa_eh_globals *globals = &ti->globals;
-	globals->uncaughtExceptions--;
 	_Unwind_Exception *exceptionObject = static_cast<_Unwind_Exception*>(e);
 
 	if (isCXXException(exceptionObject->exception_class))
 	{
+		// Only exceptions thrown with a C++ exception throwing function will
+		// increment this, so don't decrement it here.
+		globals->uncaughtExceptions--;
 		__cxa_exception *ex =  exceptionFromPointer(exceptionObject);
 
 		if (ex->handlerCount == 0)
@@ -1280,12 +1294,13 @@ extern "C" void __cxa_end_catch()
 	
 	if (ti->foreign_exception_state != __cxa_thread_info::none)
 	{
-		globals->caughtExceptions = 0;
 		if (ti->foreign_exception_state != __cxa_thread_info::rethrown)
 		{
 			_Unwind_Exception *e = reinterpret_cast<_Unwind_Exception*>(ti->globals.caughtExceptions);
-			e->exception_cleanup(_URC_FOREIGN_EXCEPTION_CAUGHT, e);
+			if (e->exception_cleanup)
+				e->exception_cleanup(_URC_FOREIGN_EXCEPTION_CAUGHT, e);
 		}
+		globals->caughtExceptions = 0;
 		ti->foreign_exception_state = __cxa_thread_info::none;
 		return;
 	}
@@ -1339,6 +1354,14 @@ extern "C" std::type_info *__cxa_current
 }
 
 /**
+ * Cleanup, ensures that `__cxa_end_catch` is called to balance an explicit
+ * `__cxa_begin_catch` call.
+ */
+static void end_catch(char *)
+{
+	__cxa_end_catch();
+}
+/**
  * ABI function, called when an exception specification is violated.
  *
  * This function does not return.
@@ -1346,6 +1369,12 @@ extern "C" std::type_info *__cxa_current
 extern "C" void __cxa_call_unexpected(void*exception) 
 {
 	_Unwind_Exception *exceptionObject = static_cast<_Unwind_Exception*>(exception);
+	// Wrap the call to the unexpected handler in calls to `__cxa_begin_catch`
+	// and `__cxa_end_catch` so that we correctly update exception counts if
+	// the unexpected handler throws an exception.
+	__cxa_begin_catch(exceptionObject);
+	__attribute__((cleanup(end_catch)))
+	char unused;
 	if (exceptionObject->exception_class == exception_class)
 	{
 		__cxa_exception *ex =  exceptionFromPointer(exceptionObject);
@@ -1472,6 +1501,15 @@ namespace std
 		return info->globals.uncaughtExceptions != 0;
 	}
 	/**
+	 * Returns the number of exceptions currently being thrown that have not
+	 * been caught.  This can occur inside a nested catch statement.
+	 */
+	int uncaught_exceptions() throw()
+	{
+		__cxa_thread_info *info = thread_info();
+		return info->globals.uncaughtExceptions;
+	}
+	/**
 	 * Returns the current unexpected handler.
 	 */
 	unexpected_handler get_unexpected() throw()
Index: src/external/bsd/libc++/dist/libcxxrt/src/libelftc_dem_gnu3.c
diff -u src/external/bsd/libc++/dist/libcxxrt/src/libelftc_dem_gnu3.c:1.2 src/external/bsd/libc++/dist/libcxxrt/src/libelftc_dem_gnu3.c:1.3
--- src/external/bsd/libc++/dist/libcxxrt/src/libelftc_dem_gnu3.c:1.2	Tue Aug  1 18:08:48 2017
+++ src/external/bsd/libc++/dist/libcxxrt/src/libelftc_dem_gnu3.c	Sun May 30 00:12:31 2021
@@ -1,5 +1,6 @@
 /*-
- * Copyright (c) 2007, 2008 Hyogeol Lee <hyogeol...@gmail.com>
+ * Copyright (c) 2007 Hyogeol Lee <hyogeol...@gmail.com>
+ * Copyright (c) 2015-2017 Kai Wang <kaiwan...@gmail.com>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -54,12 +55,17 @@ struct vector_str {
 };
 
 #define BUFFER_GROWFACTOR	1.618
-#define VECTOR_DEF_CAPACITY	8
+#define BUFFER_GROW(x)		(((x)+0.5)*BUFFER_GROWFACTOR)
+
+#define	ELFTC_FAILURE		0
 #define	ELFTC_ISDIGIT(C) 	(isdigit((C) & 0xFF))
+#define	ELFTC_SUCCESS		1
+
+#define VECTOR_DEF_CAPACITY	8
 
 enum type_qualifier {
 	TYPE_PTR, TYPE_REF, TYPE_CMX, TYPE_IMG, TYPE_EXT, TYPE_RST, TYPE_VAT,
-	TYPE_CST, TYPE_VEC
+	TYPE_CST, TYPE_VEC, TYPE_RREF
 };
 
 struct vector_type_qualifier {
@@ -73,27 +79,47 @@ enum read_cmd {
 	READ_TYPE, READ_FUNC, READ_PTRMEM
 };
 
+struct read_cmd_item {
+	enum read_cmd cmd;
+	void *data;
+};
+
 struct vector_read_cmd {
 	size_t size, capacity;
-	enum read_cmd *r_container;
+	struct read_cmd_item *r_container;
+};
+
+enum push_qualifier {
+	PUSH_ALL_QUALIFIER,
+	PUSH_CV_QUALIFIER,
+	PUSH_NON_CV_QUALIFIER,
 };
 
 struct cpp_demangle_data {
 	struct vector_str	 output;	/* output string vector */
-	struct vector_str	 output_tmp;
 	struct vector_str	 subst;		/* substitution string vector */
 	struct vector_str	 tmpl;
 	struct vector_str	 class_type;
+	struct vector_str	*cur_output;	/* ptr to current output vec */
 	struct vector_read_cmd	 cmd;
-	bool			 paren;		/* parenthesis opened */
-	bool			 pfirst;	/* first element of parameter */
 	bool			 mem_rst;	/* restrict member function */
 	bool			 mem_vat;	/* volatile member function */
 	bool			 mem_cst;	/* const member function */
+	bool			 mem_ref;	/* lvalue-ref member func */
+	bool			 mem_rref;	/* rvalue-ref member func */
+	bool			 is_tmpl;	/* template args */
+	bool			 is_functype;	/* function type */
+	bool			 ref_qualifier; /* ref qualifier */
+	enum type_qualifier	 ref_qualifier_type; /* ref qualifier type */
+	enum push_qualifier	 push_qualifier; /* which qualifiers to push */
 	int			 func_type;
 	const char		*cur;		/* current mangled name ptr */
 	const char		*last_sname;	/* last source name */
-	int			 push_head;
+};
+
+struct type_delimit {
+	bool paren;
+	bool firstp;
 };
 
 #define	CPP_DEMANGLE_TRY_LIMIT	128
@@ -102,6 +128,8 @@ struct cpp_demangle_data {
 #define	FLOAT_EXTENED_BYTES	10
 
 #define SIMPLE_HASH(x,y)	(64 * x + y)
+#define DEM_PUSH_STR(d,s)	cpp_demangle_push_str((d), (s), strlen((s)))
+#define VEC_PUSH_STR(d,s)	vector_str_push((d), (s), strlen((s)))
 
 static size_t	get_strlen_sum(const struct vector_str *v);
 static bool	vector_str_grow(struct vector_str *v);
@@ -213,7 +241,7 @@ vector_str_grow(struct vector_str *v)
 
 	assert(v->capacity > 0);
 
-	tmp_cap = v->capacity * BUFFER_GROWFACTOR;
+	tmp_cap = BUFFER_GROW(v->capacity);
 
 	assert(tmp_cap > v->capacity);
 
@@ -314,7 +342,7 @@ vector_str_push_vector_head(struct vecto
 	if (dst == NULL || org == NULL)
 		return (false);
 
-	tmp_cap = (dst->size + org->size) * BUFFER_GROWFACTOR;
+	tmp_cap = BUFFER_GROW(dst->size + org->size);
 
 	if ((tmp_ctn = malloc(sizeof(char *) * tmp_cap)) == NULL)
 		return (false);
@@ -342,6 +370,47 @@ vector_str_push_vector_head(struct vecto
 }
 
 /**
+ * @brief Push org vector to the tail of det vector.
+ * @return false at failed, true at success.
+ */
+static bool
+vector_str_push_vector(struct vector_str *dst, struct vector_str *org)
+{
+	size_t i, j, tmp_cap;
+	char **tmp_ctn;
+
+	if (dst == NULL || org == NULL)
+		return (false);
+
+	tmp_cap = BUFFER_GROW(dst->size + org->size);
+
+	if ((tmp_ctn = malloc(sizeof(char *) * tmp_cap)) == NULL)
+		return (false);
+
+	for (i = 0; i < dst->size; ++i)
+		tmp_ctn[i] = dst->container[i];
+
+	for (i = 0; i < org->size; ++i)
+		if ((tmp_ctn[i + dst->size] = strdup(org->container[i])) ==
+		    NULL) {
+			for (j = 0; j < i + dst->size; ++j)
+				free(tmp_ctn[j]);
+
+			free(tmp_ctn);
+
+			return (false);
+		}
+
+	free(dst->container);
+
+	dst->container = tmp_ctn;
+	dst->capacity = tmp_cap;
+	dst->size += org->size;
+
+	return (true);
+}
+
+/**
  * @brief Get new allocated flat string from vector between begin and end.
  *
  * If r_len is not NULL, string length will be returned.
@@ -387,6 +456,7 @@ static int	cpp_demangle_push_fp(struct c
 		    char *(*)(const char *, size_t));
 static int	cpp_demangle_push_str(struct cpp_demangle_data *, const char *,
 		    size_t);
+static int	cpp_demangle_pop_str(struct cpp_demangle_data *);
 static int	cpp_demangle_push_subst(struct cpp_demangle_data *,
 		    const char *, size_t);
 static int	cpp_demangle_push_subst_v(struct cpp_demangle_data *,
@@ -419,16 +489,18 @@ static int	cpp_demangle_read_number_as_s
 static int	cpp_demangle_read_nv_offset(struct cpp_demangle_data *);
 static int	cpp_demangle_read_offset(struct cpp_demangle_data *);
 static int	cpp_demangle_read_offset_number(struct cpp_demangle_data *);
-static int	cpp_demangle_read_pointer_to_member(struct cpp_demangle_data *);
+static int	cpp_demangle_read_pointer_to_member(struct cpp_demangle_data *,
+		    struct vector_type_qualifier *);
 static int	cpp_demangle_read_sname(struct cpp_demangle_data *);
 static int	cpp_demangle_read_subst(struct cpp_demangle_data *);
 static int	cpp_demangle_read_subst_std(struct cpp_demangle_data *);
 static int	cpp_demangle_read_subst_stdtmpl(struct cpp_demangle_data *,
-		    const char *, size_t);
+		    const char *);
 static int	cpp_demangle_read_tmpl_arg(struct cpp_demangle_data *);
 static int	cpp_demangle_read_tmpl_args(struct cpp_demangle_data *);
 static int	cpp_demangle_read_tmpl_param(struct cpp_demangle_data *);
-static int	cpp_demangle_read_type(struct cpp_demangle_data *, int);
+static int	cpp_demangle_read_type(struct cpp_demangle_data *,
+		    struct type_delimit *);
 static int	cpp_demangle_read_type_flat(struct cpp_demangle_data *,
 		    char **);
 static int	cpp_demangle_read_uqname(struct cpp_demangle_data *);
@@ -440,10 +512,12 @@ static char	*decode_fp_to_float80(const 
 static char	*decode_fp_to_long_double(const char *, size_t);
 static int	hex_to_dec(char);
 static void	vector_read_cmd_dest(struct vector_read_cmd *);
-static int	vector_read_cmd_find(struct vector_read_cmd *, enum read_cmd);
+static struct read_cmd_item *vector_read_cmd_find(struct vector_read_cmd *,
+		    enum read_cmd);
 static int	vector_read_cmd_init(struct vector_read_cmd *);
 static int	vector_read_cmd_pop(struct vector_read_cmd *);
-static int	vector_read_cmd_push(struct vector_read_cmd *, enum read_cmd);
+static int	vector_read_cmd_push(struct vector_read_cmd *, enum read_cmd,
+		    void *);
 static void	vector_type_qualifier_dest(struct vector_type_qualifier *);
 static int	vector_type_qualifier_init(struct vector_type_qualifier *);
 static int	vector_type_qualifier_push(struct vector_type_qualifier *,
@@ -460,22 +534,17 @@ char *
 __cxa_demangle_gnu3(const char *org)
 {
 	struct cpp_demangle_data ddata;
+	struct vector_str ret_type;
+	struct type_delimit td;
 	ssize_t org_len;
 	unsigned int limit;
-	char *rtn = NULL;
+	char *rtn;
+	bool has_ret, more_type;
 
 	if (org == NULL)
 		return (NULL);
 
 	org_len = strlen(org);
-	if (org_len > 11 && !strncmp(org, "_GLOBAL__I_", 11)) {
-		if ((rtn = malloc(org_len + 19)) == NULL)
-			return (NULL);
-		snprintf(rtn, org_len + 19,
-		    "global constructors keyed to %s", org + 11);
-		return (rtn);
-	}
-
 	// Try demangling as a type for short encodings
 	if ((org_len < 2) || (org[0] != '_' || org[1] != 'Z' )) {
 		if (!cpp_demangle_data_init(&ddata, org))
@@ -485,43 +554,106 @@ __cxa_demangle_gnu3(const char *org)
 		rtn = vector_str_get_flat(&ddata.output, (size_t *) NULL);
 		goto clean;
 	}
+	if (org_len > 11 && !strncmp(org, "_GLOBAL__I_", 11)) {
+		if ((rtn = malloc(org_len + 19)) == NULL)
+			return (NULL);
+		snprintf(rtn, org_len + 19,
+		    "global constructors keyed to %s", org + 11);
+		return (rtn);
+	}
 
 
 	if (!cpp_demangle_data_init(&ddata, org + 2))
 		return (NULL);
 
 	rtn = NULL;
+	has_ret = more_type = false;
 
 	if (!cpp_demangle_read_encoding(&ddata))
 		goto clean;
 
+	/*
+	 * Pop function name from substitution candidate list.
+	 */
+	if (*ddata.cur != 0 && ddata.subst.size >= 1) {
+		if (!vector_str_pop(&ddata.subst))
+			goto clean;
+	}
+
+	td.paren = false;
+	td.firstp = true;
 	limit = 0;
+
+	/*
+	 * The first type is a return type if we just demangled template
+	 * args. (the template args is right next to the function name,
+	 * which means it's a template function)
+	 */
+	if (ddata.is_tmpl) {
+		ddata.is_tmpl = false;
+		if (!vector_str_init(&ret_type))
+			goto clean;
+		ddata.cur_output = &ret_type;
+		has_ret = true;
+	}
+
 	while (*ddata.cur != '\0') {
 		/*
 		 * Breaking at some gcc info at tail. e.g) @@GLIBCXX_3.4
 		 */
 		if (*ddata.cur == '@' && *(ddata.cur + 1) == '@')
 			break;
-		if (!cpp_demangle_read_type(&ddata, 1))
-			goto clean;
+
+		if (has_ret) {
+			/* Read return type */
+			if (!cpp_demangle_read_type(&ddata, NULL))
+				goto clean;
+		} else {
+			/* Read function arg type */
+			if (!cpp_demangle_read_type(&ddata, &td))
+				goto clean;
+		}
+
+		if (has_ret) {
+			/* Push return type to the beginning */
+			if (!VEC_PUSH_STR(&ret_type, " "))
+				goto clean;
+			if (!vector_str_push_vector_head(&ddata.output,
+			    &ret_type))
+				goto clean;
+			ddata.cur_output = &ddata.output;
+			vector_str_dest(&ret_type);
+			has_ret = false;
+			more_type = true;
+		} else if (more_type)
+			more_type = false;
 		if (limit++ > CPP_DEMANGLE_TRY_LIMIT)
 			goto clean;
 	}
+	if (more_type)
+		goto clean;
 
 	if (ddata.output.size == 0)
 		goto clean;
-	if (ddata.paren && !vector_str_push(&ddata.output, ")", 1))
+	if (td.paren && !VEC_PUSH_STR(&ddata.output, ")"))
+		goto clean;
+	if (ddata.mem_vat && !VEC_PUSH_STR(&ddata.output, " volatile"))
 		goto clean;
-	if (ddata.mem_vat && !vector_str_push(&ddata.output, " volatile", 9))
+	if (ddata.mem_cst && !VEC_PUSH_STR(&ddata.output, " const"))
 		goto clean;
-	if (ddata.mem_cst && !vector_str_push(&ddata.output, " const", 6))
+	if (ddata.mem_rst && !VEC_PUSH_STR(&ddata.output, " restrict"))
 		goto clean;
-	if (ddata.mem_rst && !vector_str_push(&ddata.output, " restrict", 9))
+	if (ddata.mem_ref && !VEC_PUSH_STR(&ddata.output, " &"))
+		goto clean;
+	if (ddata.mem_rref && !VEC_PUSH_STR(&ddata.output, " &&"))
 		goto clean;
 
 	rtn = vector_str_get_flat(&ddata.output, (size_t *) NULL);
 
 clean:
+	if (has_ret)
+		vector_str_dest(&ret_type);
+
 	cpp_demangle_data_dest(&ddata);
 
 	return (rtn);
@@ -538,7 +670,6 @@ cpp_demangle_data_dest(struct cpp_demang
 	vector_str_dest(&d->class_type);
 	vector_str_dest(&d->tmpl);
 	vector_str_dest(&d->subst);
-	vector_str_dest(&d->output_tmp);
 	vector_str_dest(&d->output);
 }
 
@@ -551,43 +682,42 @@ cpp_demangle_data_init(struct cpp_demang
 
 	if (!vector_str_init(&d->output))
 		return (0);
-	if (!vector_str_init(&d->output_tmp))
-		goto clean1;
 	if (!vector_str_init(&d->subst))
-		goto clean2;
+		goto clean1;
 	if (!vector_str_init(&d->tmpl))
-		goto clean3;
+		goto clean2;
 	if (!vector_str_init(&d->class_type))
-		goto clean4;
+		goto clean3;
 	if (!vector_read_cmd_init(&d->cmd))
-		goto clean5;
+		goto clean4;
 
 	assert(d->output.container != NULL);
-	assert(d->output_tmp.container != NULL);
 	assert(d->subst.container != NULL);
 	assert(d->tmpl.container != NULL);
 	assert(d->class_type.container != NULL);
 
-	d->paren = false;
-	d->pfirst = false;
 	d->mem_rst = false;
 	d->mem_vat = false;
 	d->mem_cst = false;
+	d->mem_ref = false;
+	d->mem_rref = false;
+	d->is_tmpl = false;
+	d->is_functype = false;
+	d->ref_qualifier = false;
+	d->push_qualifier = PUSH_ALL_QUALIFIER;
 	d->func_type = 0;
 	d->cur = cur;
+	d->cur_output = &d->output;
 	d->last_sname = NULL;
-	d->push_head = 0;
 
 	return (1);
 
-clean5:
-	vector_str_dest(&d->class_type);
 clean4:
-	vector_str_dest(&d->tmpl);
+	vector_str_dest(&d->class_type);
 clean3:
-	vector_str_dest(&d->subst);
+	vector_str_dest(&d->tmpl);
 clean2:
-	vector_str_dest(&d->output_tmp);
+	vector_str_dest(&d->subst);
 clean1:
 	vector_str_dest(&d->output);
 
@@ -632,10 +762,24 @@ cpp_demangle_push_str(struct cpp_demangl
 	if (ddata == NULL || str == NULL || len == 0)
 		return (0);
 
-	if (ddata->push_head > 0)
-		return (vector_str_push(&ddata->output_tmp, str, len));
+	/*
+	 * is_tmpl is used to check if the type (function arg) is right next
+	 * to template args, and should always be cleared whenever new string
+	 * pushed.
+	 */
+	ddata->is_tmpl = false;
 
-	return (vector_str_push(&ddata->output, str, len));
+	return (vector_str_push(ddata->cur_output, str, len));
+}
+
+static int
+cpp_demangle_pop_str(struct cpp_demangle_data *ddata)
+{
+
+	if (ddata == NULL)
+		return (0);
+
+	return (vector_str_pop(ddata->cur_output));
 }
 
 static int
@@ -677,9 +821,11 @@ cpp_demangle_push_type_qualifier(struct 
     struct vector_type_qualifier *v, const char *type_str)
 {
 	struct vector_str subst_v;
+	enum type_qualifier t;
 	size_t idx, e_idx, e_len;
-	int rtn;
 	char *buf;
+	int rtn;
+	bool cv;
 
 	if (ddata == NULL || v == NULL)
 		return (0);
@@ -691,18 +837,22 @@ cpp_demangle_push_type_qualifier(struct 
 	if (type_str != NULL) {
 		if (!vector_str_init(&subst_v))
 			return (0);
-		if (!vector_str_push(&subst_v, type_str, strlen(type_str)))
+		if (!VEC_PUSH_STR(&subst_v, type_str))
 			goto clean;
 	}
 
+	cv = true;
 	e_idx = 0;
 	while (idx > 0) {
 		switch (v->q_container[idx - 1]) {
 		case TYPE_PTR:
-			if (!cpp_demangle_push_str(ddata, "*", 1))
+			cv = false;
+			if (ddata->push_qualifier == PUSH_CV_QUALIFIER)
+				break;
+			if (!DEM_PUSH_STR(ddata, "*"))
 				goto clean;
 			if (type_str != NULL) {
-				if (!vector_str_push(&subst_v, "*", 1))
+				if (!VEC_PUSH_STR(&subst_v, "*"))
 					goto clean;
 				if (!cpp_demangle_push_subst_v(ddata,
 				    &subst_v))
@@ -711,10 +861,28 @@ cpp_demangle_push_type_qualifier(struct 
 			break;
 
 		case TYPE_REF:
-			if (!cpp_demangle_push_str(ddata, "&", 1))
+			cv = false;
+			if (ddata->push_qualifier == PUSH_CV_QUALIFIER)
+				break;
+			if (!DEM_PUSH_STR(ddata, "&"))
 				goto clean;
 			if (type_str != NULL) {
-				if (!vector_str_push(&subst_v, "&", 1))
+				if (!VEC_PUSH_STR(&subst_v, "&"))
+					goto clean;
+				if (!cpp_demangle_push_subst_v(ddata,
+				    &subst_v))
+					goto clean;
+			}
+			break;
+
+		case TYPE_RREF:
+			cv = false;
+			if (ddata->push_qualifier == PUSH_CV_QUALIFIER)
+				break;
+			if (!DEM_PUSH_STR(ddata, "&&"))
+				goto clean;
+			if (type_str != NULL) {
+				if (!VEC_PUSH_STR(&subst_v, "&&"))
 					goto clean;
 				if (!cpp_demangle_push_subst_v(ddata,
 				    &subst_v))
@@ -723,10 +891,13 @@ cpp_demangle_push_type_qualifier(struct 
 			break;
 
 		case TYPE_CMX:
-			if (!cpp_demangle_push_str(ddata, " complex", 8))
+			cv = false;
+			if (ddata->push_qualifier == PUSH_CV_QUALIFIER)
+				break;
+			if (!DEM_PUSH_STR(ddata, " complex"))
 				goto clean;
 			if (type_str != NULL) {
-				if (!vector_str_push(&subst_v, " complex", 8))
+				if (!VEC_PUSH_STR(&subst_v, " complex"))
 					goto clean;
 				if (!cpp_demangle_push_subst_v(ddata,
 				    &subst_v))
@@ -735,11 +906,13 @@ cpp_demangle_push_type_qualifier(struct 
 			break;
 
 		case TYPE_IMG:
-			if (!cpp_demangle_push_str(ddata, " imaginary", 10))
+			cv = false;
+			if (ddata->push_qualifier == PUSH_CV_QUALIFIER)
+				break;
+			if (!DEM_PUSH_STR(ddata, " imaginary"))
 				goto clean;
 			if (type_str != NULL) {
-				if (!vector_str_push(&subst_v, " imaginary",
-				    10))
+				if (!VEC_PUSH_STR(&subst_v, " imaginary"))
 					goto clean;
 				if (!cpp_demangle_push_subst_v(ddata,
 				    &subst_v))
@@ -748,6 +921,9 @@ cpp_demangle_push_type_qualifier(struct 
 			break;
 
 		case TYPE_EXT:
+			cv = false;
+			if (ddata->push_qualifier == PUSH_CV_QUALIFIER)
+				break;
 			if (v->ext_name.size == 0 ||
 			    e_idx > v->ext_name.size - 1)
 				goto clean;
@@ -759,14 +935,13 @@ cpp_demangle_push_type_qualifier(struct 
 			snprintf(buf, e_len + 2, " %s",
 			    v->ext_name.container[e_idx]);
 
-			if (!cpp_demangle_push_str(ddata, buf, e_len + 1)) {
+			if (!DEM_PUSH_STR(ddata, buf)) {
 				free(buf);
 				goto clean;
 			}
 
 			if (type_str != NULL) {
-				if (!vector_str_push(&subst_v, buf,
-				    e_len + 1)) {
+				if (!VEC_PUSH_STR(&subst_v, buf)) {
 					free(buf);
 					goto clean;
 				}
@@ -781,11 +956,22 @@ cpp_demangle_push_type_qualifier(struct 
 			break;
 
 		case TYPE_RST:
-			if (!cpp_demangle_push_str(ddata, " restrict", 9))
+			if (ddata->push_qualifier == PUSH_NON_CV_QUALIFIER &&
+			    cv)
+				break;
+			if (ddata->push_qualifier == PUSH_CV_QUALIFIER && !cv)
+				break;
+			if (!DEM_PUSH_STR(ddata, " restrict"))
 				goto clean;
 			if (type_str != NULL) {
-				if (!vector_str_push(&subst_v, " restrict", 9))
+				if (!VEC_PUSH_STR(&subst_v, " restrict"))
 					goto clean;
+				if (idx - 1 > 0) {
+					t = v->q_container[idx - 2];
+					if (t == TYPE_RST || t == TYPE_VAT ||
+					    t == TYPE_CST)
+						break;
+				}
 				if (!cpp_demangle_push_subst_v(ddata,
 				    &subst_v))
 					goto clean;
@@ -793,11 +979,22 @@ cpp_demangle_push_type_qualifier(struct 
 			break;
 
 		case TYPE_VAT:
-			if (!cpp_demangle_push_str(ddata, " volatile", 9))
+			if (ddata->push_qualifier == PUSH_NON_CV_QUALIFIER &&
+			    cv)
+				break;
+			if (ddata->push_qualifier == PUSH_CV_QUALIFIER && !cv)
+				break;
+			if (!DEM_PUSH_STR(ddata, " volatile"))
 				goto clean;
 			if (type_str != NULL) {
-				if (!vector_str_push(&subst_v, " volatile", 9))
+				if (!VEC_PUSH_STR(&subst_v, " volatile"))
 					goto clean;
+				if (idx - 1 > 0) {
+					t = v->q_container[idx - 2];
+					if (t == TYPE_RST || t == TYPE_VAT ||
+					    t == TYPE_CST)
+						break;
+				}
 				if (!cpp_demangle_push_subst_v(ddata,
 				    &subst_v))
 					goto clean;
@@ -805,11 +1002,22 @@ cpp_demangle_push_type_qualifier(struct 
 			break;
 
 		case TYPE_CST:
-			if (!cpp_demangle_push_str(ddata, " const", 6))
+			if (ddata->push_qualifier == PUSH_NON_CV_QUALIFIER &&
+			    cv)
+				break;
+			if (ddata->push_qualifier == PUSH_CV_QUALIFIER && !cv)
+				break;
+			if (!DEM_PUSH_STR(ddata, " const"))
 				goto clean;
 			if (type_str != NULL) {
-				if (!vector_str_push(&subst_v, " const", 6))
+				if (!VEC_PUSH_STR(&subst_v, " const"))
 					goto clean;
+				if (idx - 1 > 0) {
+					t = v->q_container[idx - 2];
+					if (t == TYPE_RST || t == TYPE_VAT ||
+					    t == TYPE_CST)
+						break;
+				}
 				if (!cpp_demangle_push_subst_v(ddata,
 				    &subst_v))
 					goto clean;
@@ -817,6 +1025,9 @@ cpp_demangle_push_type_qualifier(struct 
 			break;
 
 		case TYPE_VEC:
+			cv = false;
+			if (ddata->push_qualifier == PUSH_CV_QUALIFIER)
+				break;
 			if (v->ext_name.size == 0 ||
 			    e_idx > v->ext_name.size - 1)
 				goto clean;
@@ -827,13 +1038,12 @@ cpp_demangle_push_type_qualifier(struct 
 				goto clean;
 			snprintf(buf, e_len + 12, " __vector(%s)",
 			    v->ext_name.container[e_idx]);
-			if (!cpp_demangle_push_str(ddata, buf, e_len + 11)) {
+			if (!DEM_PUSH_STR(ddata, buf)) {
 				free(buf);
 				goto clean;
 			}
 			if (type_str != NULL) {
-				if (!vector_str_push(&subst_v, buf,
-				    e_len + 11)) {
+				if (!VEC_PUSH_STR(&subst_v, buf)) {
 					free(buf);
 					goto clean;
 				}
@@ -846,7 +1056,7 @@ cpp_demangle_push_type_qualifier(struct 
 			free(buf);
 			++e_idx;
 			break;
-		};
+		}
 		--idx;
 	}
 
@@ -907,10 +1117,10 @@ cpp_demangle_read_array(struct cpp_deman
 		if (*(++ddata->cur) == '\0')
 			return (0);
 
-		if (!cpp_demangle_read_type(ddata, 0))
+		if (!cpp_demangle_read_type(ddata, NULL))
 			return (0);
 
-		if (!cpp_demangle_push_str(ddata, "[]", 2))
+		if (!DEM_PUSH_STR(ddata, " []"))
 			return (0);
 	} else {
 		if (ELFTC_ISDIGIT(*ddata->cur) != 0) {
@@ -923,13 +1133,13 @@ cpp_demangle_read_array(struct cpp_deman
 			assert(num_len > 0);
 			if (*(++ddata->cur) == '\0')
 				return (0);
-			if (!cpp_demangle_read_type(ddata, 0))
+			if (!cpp_demangle_read_type(ddata, NULL))
 				return (0);
-			if (!cpp_demangle_push_str(ddata, "[", 1))
+			if (!DEM_PUSH_STR(ddata, " ["))
 				return (0);
 			if (!cpp_demangle_push_str(ddata, num, num_len))
 				return (0);
-			if (!cpp_demangle_push_str(ddata, "]", 1))
+			if (!DEM_PUSH_STR(ddata, "]"))
 				return (0);
 		} else {
 			p_idx = ddata->output.size;
@@ -953,11 +1163,11 @@ cpp_demangle_read_array(struct cpp_deman
 				free(exp);
 				return (0);
 			}
-			if (!cpp_demangle_read_type(ddata, 0)) {
+			if (!cpp_demangle_read_type(ddata, NULL)) {
 				free(exp);
 				return (0);
 			}
-			if (!cpp_demangle_push_str(ddata, "[", 1)) {
+			if (!DEM_PUSH_STR(ddata, " [")) {
 				free(exp);
 				return (0);
 			}
@@ -965,7 +1175,7 @@ cpp_demangle_read_array(struct cpp_deman
 				free(exp);
 				return (0);
 			}
-			if (!cpp_demangle_push_str(ddata, "]", 1)) {
+			if (!DEM_PUSH_STR(ddata, "]")) {
 				free(exp);
 				return (0);
 			}
@@ -1001,13 +1211,13 @@ cpp_demangle_read_expr_primary(struct cp
 		switch (*(++ddata->cur)) {
 		case '0':
 			ddata->cur += 2;
-			return (cpp_demangle_push_str(ddata, "false", 5));
+			return (DEM_PUSH_STR(ddata, "false"));
 		case '1':
 			ddata->cur += 2;
-			return (cpp_demangle_push_str(ddata, "true", 4));
+			return (DEM_PUSH_STR(ddata, "true"));
 		default:
 			return (0);
-		};
+		}
 
 	case 'd':
 		++ddata->cur;
@@ -1041,7 +1251,7 @@ cpp_demangle_read_expr_primary(struct cp
 	case 'x':
 	case 'y':
 		if (*(++ddata->cur) == 'n') {
-			if (!cpp_demangle_push_str(ddata, "-", 1))
+			if (!DEM_PUSH_STR(ddata, "-"))
 				return (0);
 			++ddata->cur;
 		}
@@ -1057,7 +1267,7 @@ cpp_demangle_read_expr_primary(struct cp
 
 	default:
 		return (0);
-	};
+	}
 }
 
 static int
@@ -1070,11 +1280,11 @@ cpp_demangle_read_expression(struct cpp_
 	switch (SIMPLE_HASH(*ddata->cur, *(ddata->cur + 1))) {
 	case SIMPLE_HASH('s', 't'):
 		ddata->cur += 2;
-		return (cpp_demangle_read_type(ddata, 0));
+		return (cpp_demangle_read_type(ddata, NULL));
 
 	case SIMPLE_HASH('s', 'r'):
 		ddata->cur += 2;
-		if (!cpp_demangle_read_type(ddata, 0))
+		if (!cpp_demangle_read_type(ddata, NULL))
 			return (0);
 		if (!cpp_demangle_read_uqname(ddata))
 			return (0);
@@ -1332,14 +1542,14 @@ cpp_demangle_read_expression(struct cpp_
 		/* operator sizeof */
 		ddata->cur += 2;
 		return (cpp_demangle_read_expression_unary(ddata, "sizeof", 6));
-	};
+	}
 
 	switch (*ddata->cur) {
 	case 'L':
 		return (cpp_demangle_read_expr_primary(ddata));
 	case 'T':
 		return (cpp_demangle_read_tmpl_param(ddata));
-	};
+	}
 
 	return (0);
 }
@@ -1351,8 +1561,7 @@ cpp_demangle_read_expression_flat(struct
 	size_t i, p_idx, idx, exp_len;
 	char *exp;
 
-	output = ddata->push_head > 0 ? &ddata->output_tmp :
-	    &ddata->output;
+	output = &ddata->output;
 
 	p_idx = output->size;
 
@@ -1429,8 +1638,12 @@ static int
 cpp_demangle_read_function(struct cpp_demangle_data *ddata, int *ext_c,
     struct vector_type_qualifier *v)
 {
+	struct type_delimit td;
+	struct read_cmd_item *rc;
 	size_t class_type_size, class_type_len, limit;
 	const char *class_type;
+	int i;
+	bool paren, non_cv_qualifier;
 
 	if (ddata == NULL || *ddata->cur != 'F' || v == NULL)
 		return (0);
@@ -1441,12 +1654,43 @@ cpp_demangle_read_function(struct cpp_de
 			*ext_c = 1;
 		++ddata->cur;
 	}
-	if (!cpp_demangle_read_type(ddata, 0))
+
+	/* Return type */
+	if (!cpp_demangle_read_type(ddata, NULL))
 		return (0);
+
 	if (*ddata->cur != 'E') {
-		if (!cpp_demangle_push_str(ddata, "(", 1))
+		if (!DEM_PUSH_STR(ddata, " "))
+			return (0);
+
+		non_cv_qualifier = false;
+		if (v->size > 0) {
+			for (i = 0; (size_t) i < v->size; i++) {
+				if (v->q_container[i] != TYPE_RST &&
+				    v->q_container[i] != TYPE_VAT &&
+				    v->q_container[i] != TYPE_CST) {
+					non_cv_qualifier = true;
+					break;
+				}
+			}
+		}
+
+		paren = false;
+		rc = vector_read_cmd_find(&ddata->cmd, READ_PTRMEM);
+		if (non_cv_qualifier || rc != NULL) {
+			if (!DEM_PUSH_STR(ddata, "("))
+				return (0);
+			paren = true;
+		}
+
+		/* Push non-cv qualifiers. */
+		ddata->push_qualifier = PUSH_NON_CV_QUALIFIER;
+		if (!cpp_demangle_push_type_qualifier(ddata, v, NULL))
 			return (0);
-		if (vector_read_cmd_find(&ddata->cmd, READ_PTRMEM)) {
+
+		if (rc) {
+			if (non_cv_qualifier && !DEM_PUSH_STR(ddata, " "))
+				return (0);
 			if ((class_type_size = ddata->class_type.size) == 0)
 				return (0);
 			class_type =
@@ -1458,42 +1702,69 @@ cpp_demangle_read_function(struct cpp_de
 			if (!cpp_demangle_push_str(ddata, class_type,
 			    class_type_len))
 				return (0);
-			if (!cpp_demangle_push_str(ddata, "::*", 3))
-				return (0);
-			++ddata->func_type;
-		} else {
-			if (!cpp_demangle_push_type_qualifier(ddata, v,
-			    (const char *) NULL))
+			if (!DEM_PUSH_STR(ddata, "::*"))
 				return (0);
-			vector_type_qualifier_dest(v);
-			if (!vector_type_qualifier_init(v))
+			/* Push pointer-to-member qualifiers. */
+			ddata->push_qualifier = PUSH_ALL_QUALIFIER;
+			if (!cpp_demangle_push_type_qualifier(ddata, rc->data,
+			    NULL))
 				return (0);
+			++ddata->func_type;
 		}
 
-		if (!cpp_demangle_push_str(ddata, ")(", 2))
-			return (0);
+		if (paren) {
+			if (!DEM_PUSH_STR(ddata, ")"))
+				return (0);
+			paren = false;
+		}
 
+		td.paren = false;
+		td.firstp = true;
 		limit = 0;
+		ddata->is_functype = true;
 		for (;;) {
-			if (!cpp_demangle_read_type(ddata, 0))
+			if (!cpp_demangle_read_type(ddata, &td))
 				return (0);
 			if (*ddata->cur == 'E')
 				break;
 			if (limit++ > CPP_DEMANGLE_TRY_LIMIT)
 				return (0);
 		}
-
-		if (vector_read_cmd_find(&ddata->cmd, READ_PTRMEM) == 1) {
-			if (!cpp_demangle_push_type_qualifier(ddata, v,
-			    (const char *) NULL))
-				return (0);
-			vector_type_qualifier_dest(v);
-			if (!vector_type_qualifier_init(v))
+		ddata->is_functype = false;
+		if (td.paren) {
+			if (!DEM_PUSH_STR(ddata, ")"))
 				return (0);
+			td.paren = false;
 		}
 
-		if (!cpp_demangle_push_str(ddata, ")", 1))
+		/* Push CV qualifiers. */
+		ddata->push_qualifier = PUSH_CV_QUALIFIER;
+		if (!cpp_demangle_push_type_qualifier(ddata, v, NULL))
+			return (0);
+
+		ddata->push_qualifier = PUSH_ALL_QUALIFIER;
+
+		/* Release type qualifier vector. */
+		vector_type_qualifier_dest(v);
+		if (!vector_type_qualifier_init(v))
 			return (0);
+
+		/* Push ref-qualifiers. */
+		if (ddata->ref_qualifier) {
+			switch (ddata->ref_qualifier_type) {
+			case TYPE_REF:
+				if (!DEM_PUSH_STR(ddata, " &"))
+					return (0);
+				break;
+			case TYPE_RREF:
+				if (!DEM_PUSH_STR(ddata, " &&"))
+					return (0);
+				break;
+			default:
+				return (0);
+			}
+			ddata->ref_qualifier = false;
+		}
 	}
 
 	++ddata->cur;
@@ -1515,7 +1786,7 @@ cpp_demangle_read_encoding(struct cpp_de
 	/* special name */
 	switch (SIMPLE_HASH(*ddata->cur, *(ddata->cur + 1))) {
 	case SIMPLE_HASH('G', 'A'):
-		if (!cpp_demangle_push_str(ddata, "hidden alias for ", 17))
+		if (!DEM_PUSH_STR(ddata, "hidden alias for "))
 			return (0);
 		ddata->cur += 2;
 		if (*ddata->cur == '\0')
@@ -1523,7 +1794,7 @@ cpp_demangle_read_encoding(struct cpp_de
 		return (cpp_demangle_read_encoding(ddata));
 
 	case SIMPLE_HASH('G', 'R'):
-		if (!cpp_demangle_push_str(ddata, "reference temporary #", 21))
+		if (!DEM_PUSH_STR(ddata, "reference temporary #"))
 			return (0);
 		ddata->cur += 2;
 		if (*ddata->cur == '\0')
@@ -1533,11 +1804,11 @@ cpp_demangle_read_encoding(struct cpp_de
 		rtn = 0;
 		if (!cpp_demangle_read_number_as_string(ddata, &num_str))
 			goto clean1;
-		if (!cpp_demangle_push_str(ddata, num_str, strlen(num_str)))
+		if (!DEM_PUSH_STR(ddata, num_str))
 			goto clean2;
-		if (!cpp_demangle_push_str(ddata, " for ", 5))
+		if (!DEM_PUSH_STR(ddata, " for "))
 			goto clean2;
-		if (!cpp_demangle_push_str(ddata, name, strlen(name)))
+		if (!DEM_PUSH_STR(ddata, name))
 			goto clean2;
 		rtn = 1;
 	clean2:
@@ -1552,29 +1823,29 @@ cpp_demangle_read_encoding(struct cpp_de
 			return (0);
 		switch (*ddata->cur) {
 		case 'n':
-			if (!cpp_demangle_push_str(ddata,
-			    "non-transaction clone for ", 26))
+			if (!DEM_PUSH_STR(ddata, "non-transaction clone for "))
 				return (0);
+			break;
 		case 't':
 		default:
-			if (!cpp_demangle_push_str(ddata,
-			    "transaction clone for ", 22))
+			if (!DEM_PUSH_STR(ddata, "transaction clone for "))
 				return (0);
+			break;
 		}
 		++ddata->cur;
 		return (cpp_demangle_read_encoding(ddata));
 
 	case SIMPLE_HASH('G', 'V'):
 		/* sentry object for 1 time init */
-		if (!cpp_demangle_push_str(ddata, "guard variable for ", 20))
+		if (!DEM_PUSH_STR(ddata, "guard variable for "))
 			return (0);
 		ddata->cur += 2;
 		break;
 
 	case SIMPLE_HASH('T', 'c'):
 		/* virtual function covariant override thunk */
-		if (!cpp_demangle_push_str(ddata,
-		    "virtual function covariant override ", 36))
+		if (!DEM_PUSH_STR(ddata,
+		    "virtual function covariant override "))
 			return (0);
 		ddata->cur += 2;
 		if (*ddata->cur == '\0')
@@ -1587,8 +1858,7 @@ cpp_demangle_read_encoding(struct cpp_de
 
 	case SIMPLE_HASH('T', 'C'):
 		/* construction vtable */
-		if (!cpp_demangle_push_str(ddata, "construction vtable for ",
-		    24))
+		if (!DEM_PUSH_STR(ddata, "construction vtable for "))
 			return (0);
 		ddata->cur += 2;
 		if (*ddata->cur == '\0')
@@ -1600,11 +1870,11 @@ cpp_demangle_read_encoding(struct cpp_de
 			goto clean3;
 		if (*ddata->cur++ != '_')
 			goto clean3;
-		if (!cpp_demangle_read_type(ddata, 0))
+		if (!cpp_demangle_read_type(ddata, NULL))
 			goto clean3;
-		if (!cpp_demangle_push_str(ddata, "-in-", 4))
+		if (!DEM_PUSH_STR(ddata, "-in-"))
 			goto clean3;
-		if (!cpp_demangle_push_str(ddata, type, strlen(type)))
+		if (!DEM_PUSH_STR(ddata, type))
 			goto clean3;
 		rtn = 1;
 	clean3:
@@ -1617,17 +1887,17 @@ cpp_demangle_read_encoding(struct cpp_de
 
 	case SIMPLE_HASH('T', 'F'):
 		/* typeinfo fn */
-		if (!cpp_demangle_push_str(ddata, "typeinfo fn for ", 16))
+		if (!DEM_PUSH_STR(ddata, "typeinfo fn for "))
 			return (0);
 		ddata->cur += 2;
 		if (*ddata->cur == '\0')
 			return (0);
-		return (cpp_demangle_read_type(ddata, 0));
+		return (cpp_demangle_read_type(ddata, NULL));
 
 	case SIMPLE_HASH('T', 'h'):
 		/* virtual function non-virtual override thunk */
-		if (!cpp_demangle_push_str(ddata,
-		    "virtual function non-virtual override ", 38))
+		if (!DEM_PUSH_STR(ddata,
+		    "virtual function non-virtual override "))
 			return (0);
 		ddata->cur += 2;
 		if (*ddata->cur == '\0')
@@ -1638,8 +1908,7 @@ cpp_demangle_read_encoding(struct cpp_de
 
 	case SIMPLE_HASH('T', 'H'):
 		/* TLS init function */
-		if (!cpp_demangle_push_str(ddata, "TLS init function for ",
-		    22))
+		if (!DEM_PUSH_STR(ddata, "TLS init function for "))
 			return (0);
 		ddata->cur += 2;
 		if (*ddata->cur == '\0')
@@ -1648,44 +1917,43 @@ cpp_demangle_read_encoding(struct cpp_de
 
 	case SIMPLE_HASH('T', 'I'):
 		/* typeinfo structure */
-		if (!cpp_demangle_push_str(ddata, "typeinfo for ", 13))
+		if (!DEM_PUSH_STR(ddata, "typeinfo for "))
 			return (0);
 		ddata->cur += 2;
 		if (*ddata->cur == '\0')
 			return (0);
-		return (cpp_demangle_read_type(ddata, 0));
+		return (cpp_demangle_read_type(ddata, NULL));
 
 	case SIMPLE_HASH('T', 'J'):
 		/* java class */
-		if (!cpp_demangle_push_str(ddata, "java Class for ", 15))
+		if (!DEM_PUSH_STR(ddata, "java Class for "))
 			return (0);
 		ddata->cur += 2;
 		if (*ddata->cur == '\0')
 			return (0);
-		return (cpp_demangle_read_type(ddata, 0));
+		return (cpp_demangle_read_type(ddata, NULL));
 
 	case SIMPLE_HASH('T', 'S'):
 		/* RTTI name (NTBS) */
-		if (!cpp_demangle_push_str(ddata, "typeinfo name for ", 18))
+		if (!DEM_PUSH_STR(ddata, "typeinfo name for "))
 			return (0);
 		ddata->cur += 2;
 		if (*ddata->cur == '\0')
 			return (0);
-		return (cpp_demangle_read_type(ddata, 0));
+		return (cpp_demangle_read_type(ddata, NULL));
 
 	case SIMPLE_HASH('T', 'T'):
 		/* VTT table */
-		if (!cpp_demangle_push_str(ddata, "VTT for ", 8))
+		if (!DEM_PUSH_STR(ddata, "VTT for "))
 			return (0);
 		ddata->cur += 2;
 		if (*ddata->cur == '\0')
 			return (0);
-		return (cpp_demangle_read_type(ddata, 0));
+		return (cpp_demangle_read_type(ddata, NULL));
 
 	case SIMPLE_HASH('T', 'v'):
 		/* virtual function virtual override thunk */
-		if (!cpp_demangle_push_str(ddata,
-		    "virtual function virtual override ", 34))
+		if (!DEM_PUSH_STR(ddata, "virtual function virtual override "))
 			return (0);
 		ddata->cur += 2;
 		if (*ddata->cur == '\0')
@@ -1696,23 +1964,22 @@ cpp_demangle_read_encoding(struct cpp_de
 
 	case SIMPLE_HASH('T', 'V'):
 		/* virtual table */
-		if (!cpp_demangle_push_str(ddata, "vtable for ", 12))
+		if (!DEM_PUSH_STR(ddata, "vtable for "))
 			return (0);
 		ddata->cur += 2;
 		if (*ddata->cur == '\0')
 			return (0);
-		return (cpp_demangle_read_type(ddata, 0));
+		return (cpp_demangle_read_type(ddata, NULL));
 
 	case SIMPLE_HASH('T', 'W'):
 		/* TLS wrapper function */
-		if (!cpp_demangle_push_str(ddata, "TLS wrapper function for ",
-		    25))
+		if (!DEM_PUSH_STR(ddata, "TLS wrapper function for "))
 			return (0);
 		ddata->cur += 2;
 		if (*ddata->cur == '\0')
 			return (0);
 		break;
-	};
+	}
 
 	return (cpp_demangle_read_name(ddata));
 }
@@ -1720,35 +1987,80 @@ cpp_demangle_read_encoding(struct cpp_de
 static int
 cpp_demangle_read_local_name(struct cpp_demangle_data *ddata)
 {
+	struct vector_str local_name;
+	struct type_delimit td;
 	size_t limit;
+	bool  more_type;
 
 	if (ddata == NULL)
 		return (0);
 	if (*(++ddata->cur) == '\0')
 		return (0);
-	if (!cpp_demangle_read_encoding(ddata))
+
+	if (!vector_str_init(&local_name))
 		return (0);
+	ddata->cur_output = &local_name;
+
+	if (!cpp_demangle_read_encoding(ddata)) {
+		vector_str_dest(&local_name);
+		return (0);
+	}
 
+	ddata->cur_output = &ddata->output;
+
+	td.paren = false;
+	td.firstp = true;
+	more_type = false;
 	limit = 0;
-	for (;;) {
-		if (!cpp_demangle_read_type(ddata, 1))
+
+	/*
+	 * The first type is a return type if we just demangled template
+	 * args. (the template args is right next to the function name,
+	 * which means it's a template function)
+	 */
+	if (ddata->is_tmpl) {
+		ddata->is_tmpl = false;
+
+		/* Read return type */
+		if (!cpp_demangle_read_type(ddata, NULL)) {
+			vector_str_dest(&local_name);
 			return (0);
+		}
+
+		more_type = true;
+	}
+
+	/* Now we can push the name after possible return type is handled. */
+	if (!vector_str_push_vector(&ddata->output, &local_name)) {
+		vector_str_dest(&local_name);
+		return (0);
+	}
+	vector_str_dest(&local_name);
+
+	while (*ddata->cur != '\0') {
+		if (!cpp_demangle_read_type(ddata, &td))
+			return (0);
+		if (more_type)
+			more_type = false;
 		if (*ddata->cur == 'E')
 			break;
 		if (limit++ > CPP_DEMANGLE_TRY_LIMIT)
 			return (0);
 	}
+	if (more_type)
+		return (0);
+
 	if (*(++ddata->cur) == '\0')
 		return (0);
-	if (ddata->paren == true) {
-		if (!cpp_demangle_push_str(ddata, ")", 1))
+	if (td.paren == true) {
+		if (!DEM_PUSH_STR(ddata, ")"))
 			return (0);
-		ddata->paren = false;
+		td.paren = false;
 	}
 	if (*ddata->cur == 's')
 		++ddata->cur;
 	else {
-		if (!cpp_demangle_push_str(ddata, "::", 2))
+		if (!DEM_PUSH_STR(ddata, "::"))
 			return (0);
 		if (!cpp_demangle_read_name(ddata))
 			return (0);
@@ -1773,7 +2085,7 @@ cpp_demangle_read_name(struct cpp_demang
 	if (ddata == NULL || *ddata->cur == '\0')
 		return (0);
 
-	output = ddata->push_head > 0 ? &ddata->output_tmp : &ddata->output;
+	output = ddata->cur_output;
 
 	subst_str = NULL;
 
@@ -1784,7 +2096,7 @@ cpp_demangle_read_name(struct cpp_demang
 		return (cpp_demangle_read_nested_name(ddata));
 	case 'Z':
 		return (cpp_demangle_read_local_name(ddata));
-	};
+	}
 
 	if (!vector_str_init(&v))
 		return (0);
@@ -1835,8 +2147,7 @@ cpp_demangle_read_name_flat(struct cpp_d
 	size_t i, p_idx, idx, name_len;
 	char *name;
 
-	output = ddata->push_head > 0 ? &ddata->output_tmp :
-	    &ddata->output;
+	output = ddata->cur_output;
 
 	p_idx = output->size;
 
@@ -1873,8 +2184,7 @@ cpp_demangle_read_nested_name(struct cpp
 	if (*(++ddata->cur) == '\0')
 		return (0);
 
-	while (*ddata->cur == 'r' || *ddata->cur == 'V' ||
-	    *ddata->cur == 'K') {
+	do {
 		switch (*ddata->cur) {
 		case 'r':
 			ddata->mem_rst = true;
@@ -1885,11 +2195,19 @@ cpp_demangle_read_nested_name(struct cpp
 		case 'K':
 			ddata->mem_cst = true;
 			break;
-		};
-		++ddata->cur;
-	}
+		case 'R':
+			ddata->mem_ref = true;
+			break;
+		case 'O':
+			ddata->mem_rref = true;
+			break;
+		default:
+			goto next;
+		}
+	} while (*(++ddata->cur));
 
-	output = ddata->push_head > 0 ? &ddata->output_tmp : &ddata->output;
+next:
+	output = ddata->cur_output;
 	if (!vector_str_init(&v))
 		return (0);
 
@@ -1913,8 +2231,10 @@ cpp_demangle_read_nested_name(struct cpp
 		default:
 			if (!cpp_demangle_read_uqname(ddata))
 				goto clean;
-		};
+		}
 
+		if (p_idx == output->size)
+			goto next_comp;
 		if ((subst_str = vector_str_substr(output, p_idx,
 		    output->size - 1, &subst_str_len)) == NULL)
 			goto clean;
@@ -1926,13 +2246,15 @@ cpp_demangle_read_nested_name(struct cpp
 
 		if (!cpp_demangle_push_subst_v(ddata, &v))
 			goto clean;
+
+	next_comp:
 		if (*ddata->cur == 'E')
 			break;
-		else if (*ddata->cur != 'I' &&
-		    *ddata->cur != 'C' && *ddata->cur != 'D') {
-			if (!cpp_demangle_push_str(ddata, "::", 2))
+		else if (*ddata->cur != 'I' && *ddata->cur != 'C' &&
+		    *ddata->cur != 'D' && p_idx != output->size) {
+			if (!DEM_PUSH_STR(ddata, "::"))
 				goto clean;
-			if (!vector_str_push(&v, "::", 2))
+			if (!VEC_PUSH_STR(&v, "::"))
 				goto clean;
 		}
 		if (limit++ > CPP_DEMANGLE_TRY_LIMIT)
@@ -2010,7 +2332,7 @@ cpp_demangle_read_nv_offset(struct cpp_d
 	if (ddata == NULL)
 		return (0);
 
-	if (!cpp_demangle_push_str(ddata, "offset : ", 9))
+	if (!DEM_PUSH_STR(ddata, "offset : "))
 		return (0);
 
 	return (cpp_demangle_read_offset_number(ddata));
@@ -2056,14 +2378,14 @@ cpp_demangle_read_offset_number(struct c
 	while (*ddata->cur != '_')
 		++ddata->cur;
 
-	if (negative && !cpp_demangle_push_str(ddata, "-", 1))
+	if (negative && !DEM_PUSH_STR(ddata, "-"))
 		return (0);
 
 	assert(start != NULL);
 
 	if (!cpp_demangle_push_str(ddata, start, ddata->cur - start))
 		return (0);
-	if (!cpp_demangle_push_str(ddata, " ", 1))
+	if (!DEM_PUSH_STR(ddata, " "))
 		return (0);
 
 	++ddata->cur;
@@ -2072,7 +2394,8 @@ cpp_demangle_read_offset_number(struct c
 }
 
 static int
-cpp_demangle_read_pointer_to_member(struct cpp_demangle_data *ddata)
+cpp_demangle_read_pointer_to_member(struct cpp_demangle_data *ddata,
+    struct vector_type_qualifier *v)
 {
 	size_t class_type_len, i, idx, p_idx;
 	int p_func_type, rtn;
@@ -2082,7 +2405,7 @@ cpp_demangle_read_pointer_to_member(stru
 		return (0);
 
 	p_idx = ddata->output.size;
-	if (!cpp_demangle_read_type(ddata, 0))
+	if (!cpp_demangle_read_type(ddata, NULL))
 		return (0);
 
 	if ((class_type = vector_str_substr(&ddata->output, p_idx,
@@ -2095,22 +2418,22 @@ cpp_demangle_read_pointer_to_member(stru
 		if (!vector_str_pop(&ddata->output))
 			goto clean1;
 
-	if (!vector_read_cmd_push(&ddata->cmd, READ_PTRMEM))
+	if (!vector_read_cmd_push(&ddata->cmd, READ_PTRMEM, v))
 		goto clean1;
 
 	if (!vector_str_push(&ddata->class_type, class_type, class_type_len))
 		goto clean2;
 
 	p_func_type = ddata->func_type;
-	if (!cpp_demangle_read_type(ddata, 0))
+	if (!cpp_demangle_read_type(ddata, NULL))
 		goto clean3;
 
 	if (p_func_type == ddata->func_type) {
-		if (!cpp_demangle_push_str(ddata, " ", 1))
+		if (!DEM_PUSH_STR(ddata, " "))
 			goto clean3;
 		if (!cpp_demangle_push_str(ddata, class_type, class_type_len))
 			goto clean3;
-		if (!cpp_demangle_push_str(ddata, "::*", 3))
+		if (!DEM_PUSH_STR(ddata, "::*"))
 			goto clean3;
 	}
 
@@ -2124,6 +2447,10 @@ clean2:
 clean1:
 	free(class_type);
 
+	vector_type_qualifier_dest(v);
+	if (!vector_type_qualifier_init(v))
+		return (0);
+
 	return (rtn);
 }
 
@@ -2139,17 +2466,17 @@ cpp_demangle_read_sname(struct cpp_deman
 		return (0);
 
 	if (len == 12 && (memcmp("_GLOBAL__N_1", ddata->cur, 12) == 0))
-		err = cpp_demangle_push_str(ddata, "(anonymous namespace)", 21);
+		err = DEM_PUSH_STR(ddata, "(anonymous namespace)");
 	else
 		err = cpp_demangle_push_str(ddata, ddata->cur, len);
 
 	if (err == 0)
 		return (0);
 
-	assert(ddata->output.size > 0);
-	if (vector_read_cmd_find(&ddata->cmd, READ_TMPL) == 0)
+	assert(ddata->cur_output->size > 0);
+	if (vector_read_cmd_find(&ddata->cmd, READ_TMPL) == NULL)
 		ddata->last_sname =
-		    ddata->output.container[ddata->output.size - 1];
+		    ddata->cur_output->container[ddata->output.size - 1];
 
 	ddata->cur += len;
 
@@ -2168,55 +2495,61 @@ cpp_demangle_read_subst(struct cpp_deman
 	switch (SIMPLE_HASH(*ddata->cur, *(ddata->cur + 1))) {
 	case SIMPLE_HASH('S', 'a'):
 		/* std::allocator */
-		if (cpp_demangle_push_str(ddata, "std::allocator", 14) == 0)
+		if (!DEM_PUSH_STR(ddata, "std::allocator"))
 			return (0);
 		ddata->cur += 2;
 		if (*ddata->cur == 'I')
 			return (cpp_demangle_read_subst_stdtmpl(ddata,
-			    "std::allocator", 14));
+			    "std::allocator"));
 		return (1);
 
 	case SIMPLE_HASH('S', 'b'):
 		/* std::basic_string */
-		if (!cpp_demangle_push_str(ddata, "std::basic_string", 17))
+		if (!DEM_PUSH_STR(ddata, "std::basic_string"))
 			return (0);
 		ddata->cur += 2;
 		if (*ddata->cur == 'I')
 			return (cpp_demangle_read_subst_stdtmpl(ddata,
-			    "std::basic_string", 17));
+			    "std::basic_string"));
 		return (1);
 
 	case SIMPLE_HASH('S', 'd'):
 		/* std::basic_iostream<char, std::char_traits<char> > */
-		if (!cpp_demangle_push_str(ddata, "std::iostream", 19))
+		if (!DEM_PUSH_STR(ddata, "std::basic_iostream<char, "
+		    "std::char_traits<char> >"))
 			return (0);
-		ddata->last_sname = "iostream";
+		ddata->last_sname = "basic_iostream";
 		ddata->cur += 2;
 		if (*ddata->cur == 'I')
 			return (cpp_demangle_read_subst_stdtmpl(ddata,
-			    "std::iostream", 19));
+			    "std::basic_iostream<char, std::char_traits"
+				"<char> >"));
 		return (1);
 
 	case SIMPLE_HASH('S', 'i'):
 		/* std::basic_istream<char, std::char_traits<char> > */
-		if (!cpp_demangle_push_str(ddata, "std::istream", 18))
+		if (!DEM_PUSH_STR(ddata, "std::basic_istream<char, "
+		    "std::char_traits<char> >"))
 			return (0);
-		ddata->last_sname = "istream";
+		ddata->last_sname = "basic_istream";
 		ddata->cur += 2;
 		if (*ddata->cur == 'I')
 			return (cpp_demangle_read_subst_stdtmpl(ddata,
-			    "std::istream", 18));
+			    "std::basic_istream<char, std::char_traits"
+				"<char> >"));
 		return (1);
 
 	case SIMPLE_HASH('S', 'o'):
 		/* std::basic_ostream<char, std::char_traits<char> > */
-		if (!cpp_demangle_push_str(ddata, "std::ostream", 18))
+		if (!DEM_PUSH_STR(ddata, "std::basic_ostream<char, "
+		    "std::char_traits<char> >"))
 			return (0);
-		ddata->last_sname = "istream";
+		ddata->last_sname = "basic_ostream";
 		ddata->cur += 2;
 		if (*ddata->cur == 'I')
 			return (cpp_demangle_read_subst_stdtmpl(ddata,
-			    "std::ostream", 18));
+			    "std::basic_ostream<char, std::char_traits"
+				"<char> >"));
 		return (1);
 
 	case SIMPLE_HASH('S', 's'):
@@ -2226,23 +2559,33 @@ cpp_demangle_read_subst(struct cpp_deman
 		 *
 		 * a.k.a std::string
 		 */
-		if (!cpp_demangle_push_str(ddata, "std::string", 11))
+		if (!DEM_PUSH_STR(ddata, "std::basic_string<char, "
+		    "std::char_traits<char>, std::allocator<char> >"))
 			return (0);
 		ddata->last_sname = "string";
 		ddata->cur += 2;
 		if (*ddata->cur == 'I')
 			return (cpp_demangle_read_subst_stdtmpl(ddata,
-			    "std::string", 11));
+			    "std::basic_string<char, std::char_traits<char>,"
+				" std::allocator<char> >"));
 		return (1);
 
 	case SIMPLE_HASH('S', 't'):
 		/* std:: */
 		return (cpp_demangle_read_subst_std(ddata));
-	};
+	}
 
 	if (*(++ddata->cur) == '\0')
 		return (0);
 
+	/* Skip unknown substitution abbreviations. */
+	if (!(*ddata->cur >= '0' && *ddata->cur <= '9') &&
+	    !(*ddata->cur >= 'A' && *ddata->cur <= 'Z') &&
+	    *ddata->cur != '_') {
+		++ddata->cur;
+		return (1);
+	}
+
 	/* substitution */
 	if (*ddata->cur == '_')
 		return (cpp_demangle_get_subst(ddata, 0));
@@ -2284,15 +2627,15 @@ cpp_demangle_read_subst_std(struct cpp_d
 
 	subst_str = NULL;
 	rtn = 0;
-	if (!cpp_demangle_push_str(ddata, "std::", 5))
+	if (!DEM_PUSH_STR(ddata, "std::"))
 		goto clean;
 
-	if (!vector_str_push(&v, "std::", 5))
+	if (!VEC_PUSH_STR(&v, "std::"))
 		goto clean;
 
 	ddata->cur += 2;
 
-	output = ddata->push_head > 0 ? &ddata->output_tmp : &ddata->output;
+	output = ddata->cur_output;
 
 	p_idx = output->size;
 	if (!cpp_demangle_read_uqname(ddata))
@@ -2332,17 +2675,20 @@ clean:
 
 static int
 cpp_demangle_read_subst_stdtmpl(struct cpp_demangle_data *ddata,
-    const char *str, size_t len)
+    const char *str)
 {
 	struct vector_str *output;
-	size_t p_idx, substr_len;
+	size_t p_idx, substr_len, len;
 	int rtn;
 	char *subst_str, *substr;
 
-	if (ddata == NULL || str == NULL || len == 0)
+	if (ddata == NULL || str == NULL)
+		return (0);
+
+	if ((len = strlen(str)) == 0)
 		return (0);
 
-	output = ddata->push_head > 0 ? &ddata->output_tmp : &ddata->output;
+	output = ddata->cur_output;
 
 	p_idx = output->size;
 	substr = NULL;
@@ -2385,10 +2731,13 @@ cpp_demangle_read_tmpl_arg(struct cpp_de
 	case 'L':
 		return (cpp_demangle_read_expr_primary(ddata));
 	case 'X':
-		return (cpp_demangle_read_expression(ddata));
-	};
+		++ddata->cur;
+		if (!cpp_demangle_read_expression(ddata))
+			return (0);
+		return (*ddata->cur++ == 'E');
+	}
 
-	return (cpp_demangle_read_type(ddata, 0));
+	return (cpp_demangle_read_type(ddata, NULL));
 }
 
 static int
@@ -2403,14 +2752,14 @@ cpp_demangle_read_tmpl_args(struct cpp_d
 
 	++ddata->cur;
 
-	if (!vector_read_cmd_push(&ddata->cmd, READ_TMPL))
+	if (!vector_read_cmd_push(&ddata->cmd, READ_TMPL, NULL))
 		return (0);
 
-	if (!cpp_demangle_push_str(ddata, "<", 1))
+	if (!DEM_PUSH_STR(ddata, "<"))
 		return (0);
 
 	limit = 0;
-	v = ddata->push_head > 0 ? &ddata->output_tmp : &ddata->output;
+	v = ddata->cur_output;
 	for (;;) {
 		idx = v->size;
 		if (!cpp_demangle_read_tmpl_arg(ddata))
@@ -2431,13 +2780,14 @@ cpp_demangle_read_tmpl_args(struct cpp_d
 			size = v->size;
 			assert(size > 0);
 			if (!strncmp(v->container[size - 1], ">", 1)) {
-				if (!cpp_demangle_push_str(ddata, " >", 2))
+				if (!DEM_PUSH_STR(ddata, " >"))
 					return (0);
-			} else if (!cpp_demangle_push_str(ddata, ">", 1))
+			} else if (!DEM_PUSH_STR(ddata, ">"))
 				return (0);
+			ddata->is_tmpl = true;
 			break;
 		} else if (*ddata->cur != 'I' &&
-		    !cpp_demangle_push_str(ddata, ", ", 2))
+		    !DEM_PUSH_STR(ddata, ", "))
 			return (0);
 
 		if (limit++ > CPP_DEMANGLE_TRY_LIMIT)
@@ -2486,46 +2836,42 @@ cpp_demangle_read_tmpl_param(struct cpp_
 }
 
 static int
-cpp_demangle_read_type(struct cpp_demangle_data *ddata, int delimit)
+cpp_demangle_read_type(struct cpp_demangle_data *ddata,
+    struct type_delimit *td)
 {
 	struct vector_type_qualifier v;
-	struct vector_str *output;
-	size_t p_idx, type_str_len;
+	struct vector_str *output, sv;
+	size_t p_idx, type_str_len, subst_str_len;
 	int extern_c, is_builtin;
 	long len;
-	char *type_str, *exp_str, *num_str;
+	const char *p;
+	char *type_str, *exp_str, *num_str, *subst_str;
+	bool skip_ref_qualifier, omit_void;
 
 	if (ddata == NULL)
 		return (0);
 
-	output = &ddata->output;
-	if (ddata->output.size > 0 && !strncmp(ddata->output.container[ddata->output.size - 1], ">", 1)) {
-		ddata->push_head++;
-		output = &ddata->output_tmp;
-	} else if (delimit == 1) {
-		if (ddata->paren == false) {
-			if (!cpp_demangle_push_str(ddata, "(", 1))
+	output = ddata->cur_output;
+	if (td) {
+		if (td->paren == false) {
+			if (!DEM_PUSH_STR(ddata, "("))
 				return (0);
 			if (ddata->output.size < 2)
 				return (0);
-			ddata->paren = true;
-			ddata->pfirst = true;
-			/* Need pop function name */
-			if (ddata->subst.size == 1 &&
-			    !vector_str_pop(&ddata->subst))
-				return (0);
+			td->paren = true;
 		}
 
-		if (ddata->pfirst)
-			ddata->pfirst = false;
-		else if (*ddata->cur != 'I' &&
-		    !cpp_demangle_push_str(ddata, ", ", 2))
-			return (0);
+		if (!td->firstp) {
+			if (*ddata->cur != 'I') {
+				if (!DEM_PUSH_STR(ddata, ", "))
+					return (0);
+			}
+		}
 	}
 
 	assert(output != NULL);
 	/*
-	 * [r, V, K] [P, R, C, G, U] builtin, function, class-enum, array
+	 * [r, V, K] [P, R, O, C, G, U] builtin, function, class-enum, array
 	 * pointer-to-member, template-param, template-template-param, subst
 	 */
 
@@ -2536,12 +2882,19 @@ cpp_demangle_read_type(struct cpp_demang
 	is_builtin = 1;
 	p_idx = output->size;
 	type_str = exp_str = num_str = NULL;
+	skip_ref_qualifier = false;
+
 again:
+
+	/* Clear ref-qualifier flag */
+	if (*ddata->cur != 'R' && *ddata->cur != 'O' && *ddata->cur != 'E')
+		ddata->ref_qualifier = false;
+
 	/* builtin type */
 	switch (*ddata->cur) {
 	case 'a':
 		/* signed char */
-		if (!cpp_demangle_push_str(ddata, "signed char", 11))
+		if (!DEM_PUSH_STR(ddata, "signed char"))
 			goto clean;
 		++ddata->cur;
 		goto rtn;
@@ -2555,7 +2908,7 @@ again:
 
 	case 'b':
 		/* bool */
-		if (!cpp_demangle_push_str(ddata, "bool", 4))
+		if (!DEM_PUSH_STR(ddata, "bool"))
 			goto clean;
 		++ddata->cur;
 		goto rtn;
@@ -2565,18 +2918,20 @@ again:
 		if (!vector_type_qualifier_push(&v, TYPE_CMX))
 			goto clean;
 		++ddata->cur;
+		if (td)
+			td->firstp = false;
 		goto again;
 
 	case 'c':
 		/* char */
-		if (!cpp_demangle_push_str(ddata, "char", 4))
+		if (!DEM_PUSH_STR(ddata, "char"))
 			goto clean;
 		++ddata->cur;
 		goto rtn;
 
 	case 'd':
 		/* double */
-		if (!cpp_demangle_push_str(ddata, "double", 6))
+		if (!DEM_PUSH_STR(ddata, "double"))
 			goto clean;
 		++ddata->cur;
 		goto rtn;
@@ -2584,46 +2939,57 @@ again:
 	case 'D':
 		++ddata->cur;
 		switch (*ddata->cur) {
+		case 'a':
+			/* auto */
+			if (!DEM_PUSH_STR(ddata, "auto"))
+				goto clean;
+			++ddata->cur;
+			break;
+		case 'c':
+			/* decltype(auto) */
+			if (!DEM_PUSH_STR(ddata, "decltype(auto)"))
+				goto clean;
+			++ddata->cur;
+			break;
 		case 'd':
 			/* IEEE 754r decimal floating point (64 bits) */
-			if (!cpp_demangle_push_str(ddata, "decimal64", 9))
+			if (!DEM_PUSH_STR(ddata, "decimal64"))
 				goto clean;
 			++ddata->cur;
 			break;
 		case 'e':
 			/* IEEE 754r decimal floating point (128 bits) */
-			if (!cpp_demangle_push_str(ddata, "decimal128", 10))
+			if (!DEM_PUSH_STR(ddata, "decimal128"))
 				goto clean;
 			++ddata->cur;
 			break;
 		case 'f':
 			/* IEEE 754r decimal floating point (32 bits) */
-			if (!cpp_demangle_push_str(ddata, "decimal32", 9))
+			if (!DEM_PUSH_STR(ddata, "decimal32"))
 				goto clean;
 			++ddata->cur;
 			break;
 		case 'h':
 			/* IEEE 754r half-precision floating point (16 bits) */
-			if (!cpp_demangle_push_str(ddata, "half", 4))
+			if (!DEM_PUSH_STR(ddata, "half"))
 				goto clean;
 			++ddata->cur;
 			break;
 		case 'i':
 			/* char32_t */
-			if (!cpp_demangle_push_str(ddata, "char32_t", 8))
+			if (!DEM_PUSH_STR(ddata, "char32_t"))
 				goto clean;
 			++ddata->cur;
 			break;
 		case 'n':
 			/* std::nullptr_t (i.e., decltype(nullptr)) */
-			if (!cpp_demangle_push_str(ddata, "decltype(nullptr)",
-			    17))
+			if (!DEM_PUSH_STR(ddata, "decltype(nullptr)"))
 				goto clean;
 			++ddata->cur;
 			break;
 		case 's':
 			/* char16_t */
-			if (!cpp_demangle_push_str(ddata, "char16_t", 8))
+			if (!DEM_PUSH_STR(ddata, "char16_t"))
 				goto clean;
 			++ddata->cur;
 			break;
@@ -2635,15 +3001,13 @@ again:
 				if (!cpp_demangle_read_expression_flat(ddata,
 				    &exp_str))
 					goto clean;
-				if (!vector_str_push(&v.ext_name, exp_str,
-				    strlen(exp_str)))
+				if (!VEC_PUSH_STR(&v.ext_name, exp_str))
 					goto clean;
 			} else {
 				if (!cpp_demangle_read_number_as_string(ddata,
 				    &num_str))
 					goto clean;
-				if (!vector_str_push(&v.ext_name, num_str,
-				    strlen(num_str)))
+				if (!VEC_PUSH_STR(&v.ext_name, num_str))
 					goto clean;
 			}
 			if (*ddata->cur != '_')
@@ -2651,6 +3015,8 @@ again:
 			++ddata->cur;
 			if (!vector_type_qualifier_push(&v, TYPE_VEC))
 				goto clean;
+			if (td)
+				td->firstp = false;
 			goto again;
 		default:
 			goto clean;
@@ -2659,14 +3025,24 @@ again:
 
 	case 'e':
 		/* long double */
-		if (!cpp_demangle_push_str(ddata, "long double", 11))
+		if (!DEM_PUSH_STR(ddata, "long double"))
 			goto clean;
 		++ddata->cur;
 		goto rtn;
 
+	case 'E':
+		/* unexpected end except ref-qualifiers */
+		if (ddata->ref_qualifier && ddata->is_functype) {
+			skip_ref_qualifier = true;
+			/* Pop the delimiter. */
+			cpp_demangle_pop_str(ddata);
+			goto rtn;
+		}
+		goto clean;
+
 	case 'f':
 		/* float */
-		if (!cpp_demangle_push_str(ddata, "float", 5))
+		if (!DEM_PUSH_STR(ddata, "float"))
 			goto clean;
 		++ddata->cur;
 		goto rtn;
@@ -2680,7 +3056,7 @@ again:
 
 	case 'g':
 		/* __float128 */
-		if (!cpp_demangle_push_str(ddata, "__float128", 10))
+		if (!DEM_PUSH_STR(ddata, "__float128"))
 			goto clean;
 		++ddata->cur;
 		goto rtn;
@@ -2690,25 +3066,53 @@ again:
 		if (!vector_type_qualifier_push(&v, TYPE_IMG))
 			goto clean;
 		++ddata->cur;
+		if (td)
+			td->firstp = false;
 		goto again;
 
 	case 'h':
 		/* unsigned char */
-		if (!cpp_demangle_push_str(ddata, "unsigned char", 13))
+		if (!DEM_PUSH_STR(ddata, "unsigned char"))
 			goto clean;
 		++ddata->cur;
 		goto rtn;
 
 	case 'i':
 		/* int */
-		if (!cpp_demangle_push_str(ddata, "int", 3))
+		if (!DEM_PUSH_STR(ddata, "int"))
 			goto clean;
 		++ddata->cur;
 		goto rtn;
 
+	case 'I':
+		/* template args. */
+		/* handles <substitute><template-args> */
+		p_idx = output->size;
+		if (!cpp_demangle_read_tmpl_args(ddata))
+			goto clean;
+		if ((subst_str = vector_str_substr(output, p_idx,
+		    output->size - 1, &subst_str_len)) == NULL)
+			goto clean;
+		if (!vector_str_init(&sv)) {
+			free(subst_str);
+			goto clean;
+		}
+		if (!vector_str_push(&sv, subst_str, subst_str_len)) {
+			free(subst_str);
+			vector_str_dest(&sv);
+			goto clean;
+		}
+		free(subst_str);
+		if (!cpp_demangle_push_subst_v(ddata, &sv)) {
+			vector_str_dest(&sv);
+			goto clean;
+		}
+		vector_str_dest(&sv);
+		goto rtn;
+
 	case 'j':
 		/* unsigned int */
-		if (!cpp_demangle_push_str(ddata, "unsigned int", 12))
+		if (!DEM_PUSH_STR(ddata, "unsigned int"))
 			goto clean;
 		++ddata->cur;
 		goto rtn;
@@ -2718,18 +3122,20 @@ again:
 		if (!vector_type_qualifier_push(&v, TYPE_CST))
 			goto clean;
 		++ddata->cur;
+		if (td)
+			td->firstp = false;
 		goto again;
 
 	case 'l':
 		/* long */
-		if (!cpp_demangle_push_str(ddata, "long", 4))
+		if (!DEM_PUSH_STR(ddata, "long"))
 			goto clean;
 		++ddata->cur;
 		goto rtn;
 
 	case 'm':
 		/* unsigned long */
-		if (!cpp_demangle_push_str(ddata, "unsigned long", 13))
+		if (!DEM_PUSH_STR(ddata, "unsigned long"))
 			goto clean;
 
 		++ddata->cur;
@@ -2737,30 +3143,45 @@ again:
 		goto rtn;
 	case 'M':
 		/* pointer to member */
-		if (!cpp_demangle_read_pointer_to_member(ddata))
+		if (!cpp_demangle_read_pointer_to_member(ddata, &v))
 			goto clean;
 		is_builtin = 0;
 		goto rtn;
 
 	case 'n':
 		/* __int128 */
-		if (!cpp_demangle_push_str(ddata, "__int128", 8))
+		if (!DEM_PUSH_STR(ddata, "__int128"))
 			goto clean;
 		++ddata->cur;
 		goto rtn;
 
 	case 'o':
 		/* unsigned __int128 */
-		if (!cpp_demangle_push_str(ddata, "unsigned __int128", 17))
+		if (!DEM_PUSH_STR(ddata, "unsigned __int128"))
 			goto clean;
 		++ddata->cur;
 		goto rtn;
 
+	case 'O':
+		/* rvalue reference */
+		if (ddata->ref_qualifier)
+			goto clean;
+		if (!vector_type_qualifier_push(&v, TYPE_RREF))
+			goto clean;
+		ddata->ref_qualifier = true;
+		ddata->ref_qualifier_type = TYPE_RREF;
+		++ddata->cur;
+		if (td)
+			td->firstp = false;
+		goto again;
+
 	case 'P':
 		/* pointer */
 		if (!vector_type_qualifier_push(&v, TYPE_PTR))
 			goto clean;
 		++ddata->cur;
+		if (td)
+			td->firstp = false;
 		goto again;
 
 	case 'r':
@@ -2768,18 +3189,26 @@ again:
 		if (!vector_type_qualifier_push(&v, TYPE_RST))
 			goto clean;
 		++ddata->cur;
+		if (td)
+			td->firstp = false;
 		goto again;
 
 	case 'R':
 		/* reference */
+		if (ddata->ref_qualifier)
+			goto clean;
 		if (!vector_type_qualifier_push(&v, TYPE_REF))
 			goto clean;
+		ddata->ref_qualifier = true;
+		ddata->ref_qualifier_type = TYPE_REF;
 		++ddata->cur;
+		if (td)
+			td->firstp = false;
 		goto again;
 
 	case 's':
 		/* short, local string */
-		if (!cpp_demangle_push_str(ddata, "short", 5))
+		if (!DEM_PUSH_STR(ddata, "short"))
 			goto clean;
 		++ddata->cur;
 		goto rtn;
@@ -2793,7 +3222,7 @@ again:
 
 	case 't':
 		/* unsigned short */
-		if (!cpp_demangle_push_str(ddata, "unsigned short", 14))
+		if (!DEM_PUSH_STR(ddata, "unsigned short"))
 			goto clean;
 		++ddata->cur;
 		goto rtn;
@@ -2815,20 +3244,39 @@ again:
 
 	case 'U':
 		/* vendor extended type qualifier */
+		++ddata->cur;
 		if (!cpp_demangle_read_number(ddata, &len))
 			goto clean;
 		if (len <= 0)
 			goto clean;
 		if (!vector_str_push(&v.ext_name, ddata->cur, len))
-			return (0);
+			goto clean;
 		ddata->cur += len;
 		if (!vector_type_qualifier_push(&v, TYPE_EXT))
 			goto clean;
+		if (td)
+			td->firstp = false;
 		goto again;
 
 	case 'v':
 		/* void */
-		if (!cpp_demangle_push_str(ddata, "void", 4))
+		omit_void = false;
+		if (td && td->firstp) {
+			/*
+			 * peek into next bytes and see if we should omit
+			 * the "void".
+			 */
+			omit_void = true;
+			for (p = ddata->cur + 1; *p != '\0'; p++) {
+				if (*p == 'E')
+					break;
+				if (*p != 'R' && *p != 'O') {
+					omit_void = false;
+					break;
+				}
+			}
+		}
+		if (!omit_void && !DEM_PUSH_STR(ddata, "void"))
 			goto clean;
 		++ddata->cur;
 		goto rtn;
@@ -2838,45 +3286,47 @@ again:
 		if (!vector_type_qualifier_push(&v, TYPE_VAT))
 			goto clean;
 		++ddata->cur;
+		if (td)
+			td->firstp = false;
 		goto again;
 
 	case 'w':
 		/* wchar_t */
-		if (!cpp_demangle_push_str(ddata, "wchar_t", 6))
+		if (!DEM_PUSH_STR(ddata, "wchar_t"))
 			goto clean;
 		++ddata->cur;
 		goto rtn;
 
 	case 'x':
 		/* long long */
-		if (!cpp_demangle_push_str(ddata, "long long", 9))
+		if (!DEM_PUSH_STR(ddata, "long long"))
 			goto clean;
 		++ddata->cur;
 		goto rtn;
 
 	case 'y':
 		/* unsigned long long */
-		if (!cpp_demangle_push_str(ddata, "unsigned long long", 18))
+		if (!DEM_PUSH_STR(ddata, "unsigned long long"))
 			goto clean;
 		++ddata->cur;
 		goto rtn;
 
 	case 'z':
 		/* ellipsis */
-		if (!cpp_demangle_push_str(ddata, "ellipsis", 8))
+		if (!DEM_PUSH_STR(ddata, "..."))
 			goto clean;
 		++ddata->cur;
 		goto rtn;
-	};
+	}
 
 	if (!cpp_demangle_read_name(ddata))
 		goto clean;
 
 	is_builtin = 0;
 rtn:
-	if ((type_str = vector_str_substr(output, p_idx, output->size - 1,
-	    &type_str_len)) == NULL)
-		goto clean;
+
+	type_str = vector_str_substr(output, p_idx, output->size - 1,
+	    &type_str_len);
 
 	if (is_builtin == 0) {
 		if (!vector_str_find(&ddata->subst, type_str, type_str_len) &&
@@ -2884,40 +3334,18 @@ rtn:
 			goto clean;
 	}
 
-	if (!cpp_demangle_push_type_qualifier(ddata, &v, type_str))
+	if (!skip_ref_qualifier &&
+	    !cpp_demangle_push_type_qualifier(ddata, &v, type_str))
 		goto clean;
 
+	if (td)
+		td->firstp = false;
+
 	free(type_str);
 	free(exp_str);
 	free(num_str);
 	vector_type_qualifier_dest(&v);
 
-	if (ddata->push_head > 0) {
-		if (*ddata->cur == 'I' && cpp_demangle_read_tmpl_args(ddata)
-		    == 0)
-			return (0);
-
-		if (--ddata->push_head > 0)
-			return (1);
-
-		if (!vector_str_push(&ddata->output_tmp, " ", 1))
-			return (0);
-
-		if (!vector_str_push_vector_head(&ddata->output,
-		    &ddata->output_tmp))
-			return (0);
-
-		vector_str_dest(&ddata->output_tmp);
-		if (!vector_str_init(&ddata->output_tmp))
-			return (0);
-
-		if (!cpp_demangle_push_str(ddata, "(", 1))
-			return (0);
-
-		ddata->paren = true;
-		ddata->pfirst = true;
-	}
-
 	return (1);
 clean:
 	free(type_str);
@@ -2935,12 +3363,11 @@ cpp_demangle_read_type_flat(struct cpp_d
 	size_t i, p_idx, idx, type_len;
 	char *type;
 
-	output = ddata->push_head > 0 ? &ddata->output_tmp :
-	    &ddata->output;
+	output = ddata->cur_output;
 
 	p_idx = output->size;
 
-	if (!cpp_demangle_read_type(ddata, 0))
+	if (!cpp_demangle_read_type(ddata, NULL))
 		return (0);
 
 	if ((type = vector_str_substr(output, p_idx, output->size - 1,
@@ -2976,367 +3403,365 @@ cpp_demangle_read_uqname(struct cpp_dema
 	switch (SIMPLE_HASH(*ddata->cur, *(ddata->cur + 1))) {
 	case SIMPLE_HASH('a', 'a'):
 		/* operator && */
-		if (!cpp_demangle_push_str(ddata, "operator&&", 10))
+		if (!DEM_PUSH_STR(ddata, "operator&&"))
 			return (0);
 		ddata->cur += 2;
 		return (1);
 
 	case SIMPLE_HASH('a', 'd'):
 		/* operator & (unary) */
-		if (!cpp_demangle_push_str(ddata, "operator&", 9))
+		if (!DEM_PUSH_STR(ddata, "operator&"))
 			return (0);
 		ddata->cur += 2;
 		return (1);
 
 	case SIMPLE_HASH('a', 'n'):
 		/* operator & */
-		if (!cpp_demangle_push_str(ddata, "operator&", 9))
+		if (!DEM_PUSH_STR(ddata, "operator&"))
 			return (0);
 		ddata->cur += 2;
 		return (1);
 
 	case SIMPLE_HASH('a', 'N'):
 		/* operator &= */
-		if (!cpp_demangle_push_str(ddata, "operator&=", 10))
+		if (!DEM_PUSH_STR(ddata, "operator&="))
 			return (0);
 		ddata->cur += 2;
 		return (1);
 
 	case SIMPLE_HASH('a', 'S'):
 		/* operator = */
-		if (!cpp_demangle_push_str(ddata, "operator=", 9))
+		if (!DEM_PUSH_STR(ddata, "operator="))
 			return (0);
 		ddata->cur += 2;
 		return (1);
 
 	case SIMPLE_HASH('c', 'l'):
 		/* operator () */
-		if (!cpp_demangle_push_str(ddata, "operator()", 10))
+		if (!DEM_PUSH_STR(ddata, "operator()"))
 			return (0);
 		ddata->cur += 2;
 		return (1);
 
 	case SIMPLE_HASH('c', 'm'):
 		/* operator , */
-		if (!cpp_demangle_push_str(ddata, "operator,", 9))
+		if (!DEM_PUSH_STR(ddata, "operator,"))
 			return (0);
 		ddata->cur += 2;
 		return (1);
 
 	case SIMPLE_HASH('c', 'o'):
 		/* operator ~ */
-		if (!cpp_demangle_push_str(ddata, "operator~", 9))
+		if (!DEM_PUSH_STR(ddata, "operator~"))
 			return (0);
 		ddata->cur += 2;
 		return (1);
 
 	case SIMPLE_HASH('c', 'v'):
 		/* operator (cast) */
-		if (!cpp_demangle_push_str(ddata, "operator(cast)", 14))
+		if (!DEM_PUSH_STR(ddata, "operator(cast)"))
 			return (0);
 		ddata->cur += 2;
-		return (cpp_demangle_read_type(ddata, 1));
+		return (cpp_demangle_read_type(ddata, NULL));
 
 	case SIMPLE_HASH('d', 'a'):
 		/* operator delete [] */
-		if (!cpp_demangle_push_str(ddata, "operator delete []", 18))
+		if (!DEM_PUSH_STR(ddata, "operator delete []"))
 			return (0);
 		ddata->cur += 2;
 		return (1);
 
 	case SIMPLE_HASH('d', 'e'):
 		/* operator * (unary) */
-		if (!cpp_demangle_push_str(ddata, "operator*", 9))
+		if (!DEM_PUSH_STR(ddata, "operator*"))
 			return (0);
 		ddata->cur += 2;
 		return (1);
 
 	case SIMPLE_HASH('d', 'l'):
 		/* operator delete */
-		if (!cpp_demangle_push_str(ddata, "operator delete", 15))
+		if (!DEM_PUSH_STR(ddata, "operator delete"))
 			return (0);
 		ddata->cur += 2;
 		return (1);
 
 	case SIMPLE_HASH('d', 'v'):
 		/* operator / */
-		if (!cpp_demangle_push_str(ddata, "operator/", 9))
+		if (!DEM_PUSH_STR(ddata, "operator/"))
 			return (0);
 		ddata->cur += 2;
 		return (1);
 
 	case SIMPLE_HASH('d', 'V'):
 		/* operator /= */
-		if (!cpp_demangle_push_str(ddata, "operator/=", 10))
+		if (!DEM_PUSH_STR(ddata, "operator/="))
 			return (0);
 		ddata->cur += 2;
 		return (1);
 
 	case SIMPLE_HASH('e', 'o'):
 		/* operator ^ */
-		if (!cpp_demangle_push_str(ddata, "operator^", 9))
+		if (!DEM_PUSH_STR(ddata, "operator^"))
 			return (0);
 		ddata->cur += 2;
 		return (1);
 
 	case SIMPLE_HASH('e', 'O'):
 		/* operator ^= */
-		if (!cpp_demangle_push_str(ddata, "operator^=", 10))
+		if (!DEM_PUSH_STR(ddata, "operator^="))
 			return (0);
 		ddata->cur += 2;
 		return (1);
 
 	case SIMPLE_HASH('e', 'q'):
 		/* operator == */
-		if (!cpp_demangle_push_str(ddata, "operator==", 10))
+		if (!DEM_PUSH_STR(ddata, "operator=="))
 			return (0);
 		ddata->cur += 2;
 		return (1);
 
 	case SIMPLE_HASH('g', 'e'):
 		/* operator >= */
-		if (!cpp_demangle_push_str(ddata, "operator>=", 10))
+		if (!DEM_PUSH_STR(ddata, "operator>="))
 			return (0);
 		ddata->cur += 2;
 		return (1);
 
 	case SIMPLE_HASH('g', 't'):
 		/* operator > */
-		if (!cpp_demangle_push_str(ddata, "operator>", 9))
+		if (!DEM_PUSH_STR(ddata, "operator>"))
 			return (0);
 		ddata->cur += 2;
 		return (1);
 
 	case SIMPLE_HASH('i', 'x'):
 		/* operator [] */
-		if (!cpp_demangle_push_str(ddata, "operator[]", 10))
+		if (!DEM_PUSH_STR(ddata, "operator[]"))
 			return (0);
 		ddata->cur += 2;
 		return (1);
 
 	case SIMPLE_HASH('l', 'e'):
 		/* operator <= */
-		if (!cpp_demangle_push_str(ddata, "operator<=", 10))
+		if (!DEM_PUSH_STR(ddata, "operator<="))
 			return (0);
 		ddata->cur += 2;
 		return (1);
 
 	case SIMPLE_HASH('l', 's'):
 		/* operator << */
-		if (!cpp_demangle_push_str(ddata, "operator<<", 10))
+		if (!DEM_PUSH_STR(ddata, "operator<<"))
 			return (0);
 		ddata->cur += 2;
 		return (1);
 
 	case SIMPLE_HASH('l', 'S'):
 		/* operator <<= */
-		if (!cpp_demangle_push_str(ddata, "operator<<=", 11))
+		if (!DEM_PUSH_STR(ddata, "operator<<="))
 			return (0);
 		ddata->cur += 2;
 		return (1);
 
 	case SIMPLE_HASH('l', 't'):
 		/* operator < */
-		if (!cpp_demangle_push_str(ddata, "operator<", 9))
+		if (!DEM_PUSH_STR(ddata, "operator<"))
 			return (0);
 		ddata->cur += 2;
 		return (1);
 
 	case SIMPLE_HASH('m', 'i'):
 		/* operator - */
-		if (!cpp_demangle_push_str(ddata, "operator-", 9))
+		if (!DEM_PUSH_STR(ddata, "operator-"))
 			return (0);
 		ddata->cur += 2;
 		return (1);
 
 	case SIMPLE_HASH('m', 'I'):
 		/* operator -= */
-		if (!cpp_demangle_push_str(ddata, "operator-=", 10))
+		if (!DEM_PUSH_STR(ddata, "operator-="))
 			return (0);
 		ddata->cur += 2;
 		return (1);
 
 	case SIMPLE_HASH('m', 'l'):
 		/* operator * */
-		if (!cpp_demangle_push_str(ddata, "operator*", 9))
+		if (!DEM_PUSH_STR(ddata, "operator*"))
 			return (0);
 		ddata->cur += 2;
 		return (1);
 
 	case SIMPLE_HASH('m', 'L'):
 		/* operator *= */
-		if (!cpp_demangle_push_str(ddata, "operator*=", 10))
+		if (!DEM_PUSH_STR(ddata, "operator*="))
 			return (0);
 		ddata->cur += 2;
 		return (1);
 
 	case SIMPLE_HASH('m', 'm'):
 		/* operator -- */
-		if (!cpp_demangle_push_str(ddata, "operator--", 10))
+		if (!DEM_PUSH_STR(ddata, "operator--"))
 			return (0);
 		ddata->cur += 2;
 		return (1);
 
 	case SIMPLE_HASH('n', 'a'):
 		/* operator new[] */
-		if (!cpp_demangle_push_str(ddata, "operator new []", 15))
+		if (!DEM_PUSH_STR(ddata, "operator new []"))
 			return (0);
 		ddata->cur += 2;
 		return (1);
 
 	case SIMPLE_HASH('n', 'e'):
 		/* operator != */
-		if (!cpp_demangle_push_str(ddata, "operator!=", 10))
+		if (!DEM_PUSH_STR(ddata, "operator!="))
 			return (0);
 		ddata->cur += 2;
 		return (1);
 
 	case SIMPLE_HASH('n', 'g'):
 		/* operator - (unary) */
-		if (!cpp_demangle_push_str(ddata, "operator-", 9))
+		if (!DEM_PUSH_STR(ddata, "operator-"))
 			return (0);
 		ddata->cur += 2;
 		return (1);
 
 	case SIMPLE_HASH('n', 't'):
 		/* operator ! */
-		if (!cpp_demangle_push_str(ddata, "operator!", 9))
+		if (!DEM_PUSH_STR(ddata, "operator!"))
 			return (0);
 		ddata->cur += 2;
 		return (1);
 
 	case SIMPLE_HASH('n', 'w'):
 		/* operator new */
-		if (!cpp_demangle_push_str(ddata, "operator new", 12))
+		if (!DEM_PUSH_STR(ddata, "operator new"))
 			return (0);
 		ddata->cur += 2;
 		return (1);
 
 	case SIMPLE_HASH('o', 'o'):
 		/* operator || */
-		if (!cpp_demangle_push_str(ddata, "operator||", 10))
+		if (!DEM_PUSH_STR(ddata, "operator||"))
 			return (0);
 		ddata->cur += 2;
 		return (1);
 
 	case SIMPLE_HASH('o', 'r'):
 		/* operator | */
-		if (!cpp_demangle_push_str(ddata, "operator|", 9))
+		if (!DEM_PUSH_STR(ddata, "operator|"))
 			return (0);
 		ddata->cur += 2;
 		return (1);
 
 	case SIMPLE_HASH('o', 'R'):
 		/* operator |= */
-		if (!cpp_demangle_push_str(ddata, "operator|=", 10))
+		if (!DEM_PUSH_STR(ddata, "operator|="))
 			return (0);
 		ddata->cur += 2;
 		return (1);
 
 	case SIMPLE_HASH('p', 'l'):
 		/* operator + */
-		if (!cpp_demangle_push_str(ddata, "operator+", 9))
+		if (!DEM_PUSH_STR(ddata, "operator+"))
 			return (0);
 		ddata->cur += 2;
 		return (1);
 
 	case SIMPLE_HASH('p', 'L'):
 		/* operator += */
-		if (!cpp_demangle_push_str(ddata, "operator+=", 10))
+		if (!DEM_PUSH_STR(ddata, "operator+="))
 			return (0);
 		ddata->cur += 2;
 		return (1);
 
 	case SIMPLE_HASH('p', 'm'):
 		/* operator ->* */
-		if (!cpp_demangle_push_str(ddata, "operator->*", 11))
+		if (!DEM_PUSH_STR(ddata, "operator->*"))
 			return (0);
 		ddata->cur += 2;
 		return (1);
 
 	case SIMPLE_HASH('p', 'p'):
 		/* operator ++ */
-		if (!cpp_demangle_push_str(ddata, "operator++", 10))
+		if (!DEM_PUSH_STR(ddata, "operator++"))
 			return (0);
 		ddata->cur += 2;
 		return (1);
 
 	case SIMPLE_HASH('p', 's'):
 		/* operator + (unary) */
-		if (!cpp_demangle_push_str(ddata, "operator+", 9))
+		if (!DEM_PUSH_STR(ddata, "operator+"))
 			return (0);
 		ddata->cur += 2;
 		return (1);
 
 	case SIMPLE_HASH('p', 't'):
 		/* operator -> */
-		if (!cpp_demangle_push_str(ddata, "operator->", 10))
+		if (!DEM_PUSH_STR(ddata, "operator->"))
 			return (0);
 		ddata->cur += 2;
 		return (1);
 
 	case SIMPLE_HASH('q', 'u'):
 		/* operator ? */
-		if (!cpp_demangle_push_str(ddata, "operator?", 9))
+		if (!DEM_PUSH_STR(ddata, "operator?"))
 			return (0);
 		ddata->cur += 2;
 		return (1);
 
 	case SIMPLE_HASH('r', 'm'):
 		/* operator % */
-		if (!cpp_demangle_push_str(ddata, "operator%", 9))
+		if (!DEM_PUSH_STR(ddata, "operator%"))
 			return (0);
 		ddata->cur += 2;
 		return (1);
 
 	case SIMPLE_HASH('r', 'M'):
 		/* operator %= */
-		if (!cpp_demangle_push_str(ddata, "operator%=", 10))
+		if (!DEM_PUSH_STR(ddata, "operator%="))
 			return (0);
 		ddata->cur += 2;
 		return (1);
 
 	case SIMPLE_HASH('r', 's'):
 		/* operator >> */
-		if (!cpp_demangle_push_str(ddata, "operator>>", 10))
+		if (!DEM_PUSH_STR(ddata, "operator>>"))
 			return (0);
 		ddata->cur += 2;
 		return (1);
 
 	case SIMPLE_HASH('r', 'S'):
 		/* operator >>= */
-		if (!cpp_demangle_push_str(ddata, "operator>>=", 11))
+		if (!DEM_PUSH_STR(ddata, "operator>>="))
 			return (0);
 		ddata->cur += 2;
 		return (1);
 
 	case SIMPLE_HASH('r', 'z'):
 		/* operator sizeof */
-		if (!cpp_demangle_push_str(ddata, "operator sizeof ", 16))
+		if (!DEM_PUSH_STR(ddata, "operator sizeof "))
 			return (0);
 		ddata->cur += 2;
 		return (1);
 
 	case SIMPLE_HASH('s', 'r'):
 		/* scope resolution operator */
-		if (!cpp_demangle_push_str(ddata, "scope resolution operator ",
-		    26))
+		if (!DEM_PUSH_STR(ddata, "scope resolution operator "))
 			return (0);
 		ddata->cur += 2;
 		return (1);
 
 	case SIMPLE_HASH('s', 'v'):
 		/* operator sizeof */
-		if (!cpp_demangle_push_str(ddata, "operator sizeof ", 16))
+		if (!DEM_PUSH_STR(ddata, "operator sizeof "))
 			return (0);
 		ddata->cur += 2;
 		return (1);
-	};
+	}
 
 	/* vendor extened operator */
 	if (*ddata->cur == 'v' && ELFTC_ISDIGIT(*(ddata->cur + 1))) {
-		if (!cpp_demangle_push_str(ddata, "vendor extened operator ",
-		    24))
+		if (!DEM_PUSH_STR(ddata, "vendor extened operator "))
 			return (0);
 		if (!cpp_demangle_push_str(ddata, ddata->cur + 1, 1))
 			return (0);
@@ -3347,15 +3772,13 @@ cpp_demangle_read_uqname(struct cpp_dema
 	/* ctor-dtor-name */
 	switch (SIMPLE_HASH(*ddata->cur, *(ddata->cur + 1))) {
 	case SIMPLE_HASH('C', '1'):
-		/* FALLTHROUGH */
 	case SIMPLE_HASH('C', '2'):
-		/* FALLTHROUGH */
 	case SIMPLE_HASH('C', '3'):
 		if (ddata->last_sname == NULL)
 			return (0);
 		if ((len = strlen(ddata->last_sname)) == 0)
 			return (0);
-		if (!cpp_demangle_push_str(ddata, "::", 2))
+		if (!DEM_PUSH_STR(ddata, "::"))
 			return (0);
 		if (!cpp_demangle_push_str(ddata, ddata->last_sname, len))
 			return (0);
@@ -3363,21 +3786,19 @@ cpp_demangle_read_uqname(struct cpp_dema
 		return (1);
 
 	case SIMPLE_HASH('D', '0'):
-		/* FALLTHROUGH */
 	case SIMPLE_HASH('D', '1'):
-		/* FALLTHROUGH */
 	case SIMPLE_HASH('D', '2'):
 		if (ddata->last_sname == NULL)
 			return (0);
 		if ((len = strlen(ddata->last_sname)) == 0)
 			return (0);
-		if (!cpp_demangle_push_str(ddata, "::~", 3))
+		if (!DEM_PUSH_STR(ddata, "::~"))
 			return (0);
 		if (!cpp_demangle_push_str(ddata, ddata->last_sname, len))
 			return (0);
 		ddata->cur +=2;
 		return (1);
-	};
+	}
 
 	/* source name */
 	if (ELFTC_ISDIGIT(*ddata->cur) != 0)
@@ -3426,13 +3847,13 @@ cpp_demangle_read_v_offset(struct cpp_de
 	if (ddata == NULL)
 		return (0);
 
-	if (!cpp_demangle_push_str(ddata, "offset : ", 9))
+	if (!DEM_PUSH_STR(ddata, "offset : "))
 		return (0);
 
 	if (!cpp_demangle_read_offset_number(ddata))
 		return (0);
 
-	if (!cpp_demangle_push_str(ddata, "virtual offset : ", 17))
+	if (!DEM_PUSH_STR(ddata, "virtual offset : "))
 		return (0);
 
 	return (!cpp_demangle_read_offset_number(ddata));
@@ -3624,7 +4045,7 @@ decode_fp_to_float80(const char *p, size
 #endif /* ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN */
 		}
 
-		memset(&f, 0, sizeof(f));
+		memset(&f, 0, FLOAT_QUADRUPLE_BYTES);
 
 #if ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN
 		memcpy(&f, buf, FLOAT_EXTENED_BYTES);
@@ -3740,7 +4161,23 @@ hex_to_dec(char c)
 		return (15);
 	default:
 		return (-1);
-	};
+	}
+}
+
+/**
+ * @brief Test input string is mangled by IA-64 C++ ABI style.
+ *
+ * Test string heads with "_Z" or "_GLOBAL__I_".
+ * @return Return 0 at false.
+ */
+bool
+is_cpp_mangled_gnu3(const char *org)
+{
+	size_t len;
+
+	len = strlen(org);
+	return ((len > 2 && *org == '_' && *(org + 1) == 'Z') ||
+	    (len > 11 && !strncmp(org, "_GLOBAL__I_", 11)));
 }
 
 static void
@@ -3753,20 +4190,19 @@ vector_read_cmd_dest(struct vector_read_
 	free(v->r_container);
 }
 
-/* return -1 at failed, 0 at not found, 1 at found. */
-static int
+static struct read_cmd_item *
 vector_read_cmd_find(struct vector_read_cmd *v, enum read_cmd dst)
 {
-	size_t i;
+	int i;
 
 	if (v == NULL || dst == READ_FAIL)
-		return (-1);
+		return (NULL);
 
-	for (i = 0; i < v->size; ++i)
-		if (v->r_container[i] == dst)
-			return (1);
+	for (i = (int) v->size - 1; i >= 0; i--)
+		if (v->r_container[i].cmd == dst)
+			return (&v->r_container[i]);
 
-	return (0);
+	return (NULL);
 }
 
 static int
@@ -3779,7 +4215,7 @@ vector_read_cmd_init(struct vector_read_
 	v->size = 0;
 	v->capacity = VECTOR_DEF_CAPACITY;
 
-	if ((v->r_container = malloc(sizeof(enum read_cmd) * v->capacity))
+	if ((v->r_container = malloc(sizeof(*v->r_container) * v->capacity))
 	    == NULL)
 		return (0);
 
@@ -3794,15 +4230,16 @@ vector_read_cmd_pop(struct vector_read_c
 		return (0);
 
 	--v->size;
-	v->r_container[v->size] = READ_FAIL;
+	v->r_container[v->size].cmd = READ_FAIL;
+	v->r_container[v->size].data = NULL;
 
 	return (1);
 }
 
 static int
-vector_read_cmd_push(struct vector_read_cmd *v, enum read_cmd cmd)
+vector_read_cmd_push(struct vector_read_cmd *v, enum read_cmd cmd, void *data)
 {
-	enum read_cmd *tmp_r_ctn;
+	struct read_cmd_item *tmp_r_ctn;
 	size_t tmp_cap;
 	size_t i;
 
@@ -3810,9 +4247,8 @@ vector_read_cmd_push(struct vector_read_
 		return (0);
 
 	if (v->size == v->capacity) {
-		tmp_cap = v->capacity * BUFFER_GROWFACTOR;
-		if ((tmp_r_ctn = malloc(sizeof(enum read_cmd) * tmp_cap))
-		    == NULL)
+		tmp_cap = BUFFER_GROW(v->capacity);
+		if ((tmp_r_ctn = malloc(sizeof(*tmp_r_ctn) * tmp_cap)) == NULL)
 			return (0);
 		for (i = 0; i < v->size; ++i)
 			tmp_r_ctn[i] = v->r_container[i];
@@ -3821,7 +4257,8 @@ vector_read_cmd_push(struct vector_read_
 		v->capacity = tmp_cap;
 	}
 
-	v->r_container[v->size] = cmd;
+	v->r_container[v->size].cmd = cmd;
+	v->r_container[v->size].data = data;
 	++v->size;
 
 	return (1);
@@ -3855,7 +4292,7 @@ vector_type_qualifier_init(struct vector
 
 	assert(v->q_container != NULL);
 
-	if (vector_str_init(&v->ext_name) == false) {
+	if (!vector_str_init(&v->ext_name)) {
 		free(v->q_container);
 		return (0);
 	}
@@ -3875,7 +4312,7 @@ vector_type_qualifier_push(struct vector
 		return (0);
 
 	if (v->size == v->capacity) {
-		tmp_cap = v->capacity * BUFFER_GROWFACTOR;
+		tmp_cap = BUFFER_GROW(v->capacity);
 		if ((tmp_ctn = malloc(sizeof(enum type_qualifier) * tmp_cap))
 		    == NULL)
 			return (0);
Index: src/external/bsd/libc++/dist/libcxxrt/src/unwind-itanium.h
diff -u src/external/bsd/libc++/dist/libcxxrt/src/unwind-itanium.h:1.2 src/external/bsd/libc++/dist/libcxxrt/src/unwind-itanium.h:1.3
--- src/external/bsd/libc++/dist/libcxxrt/src/unwind-itanium.h:1.2	Thu Jan 23 13:30:38 2014
+++ src/external/bsd/libc++/dist/libcxxrt/src/unwind-itanium.h	Sun May 30 00:12:31 2021
@@ -40,6 +40,7 @@ extern "C" {
 typedef enum
   {
     _URC_NO_REASON = 0,
+    _URC_OK = 0,
     _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
     _URC_FATAL_PHASE2_ERROR = 2,
     _URC_FATAL_PHASE1_ERROR = 3,

Reply via email to