checking reserved keywords and double identifiers

diff --git a/libasn1compiler/asn1c_C.c b/libasn1compiler/asn1c_C.c
index 5e0d0cd..91b15eb 100644
--- a/libasn1compiler/asn1c_C.c
+++ b/libasn1compiler/asn1c_C.c
@@ -35,6 +35,7 @@
 static int expr_elements_count(arg_t *arg, asn1p_expr_t *expr);
 static int emit_member_table(arg_t *arg, asn1p_expr_t *expr);
 static int emit_tag2member_map(arg_t *arg, tag2el_t *tag2el, int tag2el_count, const char *opt_modifier);
+static int out_identifiers_chain(arg_t *arg, int check_reserved_keywords);
 
 enum tvm_compat {
 	_TVM_SAME	= 0,	/* tags and all_tags are same */
@@ -65,7 +66,7 @@
 		&& __m->expr_type > ASN_CONSTR_MASK)			\
 		|| __m->meta_type == AMT_TYPEREF) {			\
 			GEN_INCLUDE(asn1c_type_name(arg,		\
-				__m, TNF_INCLUDE));			\
+				__m, TNF_INCLUDE));	\
 		}							\
 	}								\
 	if(expr->expr_type == ASN_CONSTR_SET_OF)			\
@@ -74,7 +75,9 @@
 		GEN_INCLUDE("asn_SEQUENCE_OF");				\
 } while(0)
 
-#define	MKID(id)	asn1c_make_identifier(0, (id), 0)
+/* MKID() without checking for reserved keywords */
+#define	MKID_nr(id)	asn1c_make_identifier(0, (id), 0)
+#define	MKID(id)	asn1c_make_identifier(AMI_CHECK_RESERVED, (id), 0)
 
 int
 asn1c_lang_C_type_REAL(arg_t *arg) {
@@ -126,7 +129,7 @@
 	DEPENDENCIES;
 
 	if(arg->embed) {
-		OUT("struct %s {\n", MKID(expr->Identifier));
+		OUT("struct "); out_identifiers_chain(arg, 1); OUT(" {\n");
 	} else {
 		OUT("typedef struct %s {\n",
 			MKID(expr->Identifier));
@@ -184,7 +187,7 @@
 	if(expr_elements_count(arg, expr)) {
 		int comp_mode = 0;	/* {root,ext=1,root,root,...} */
 
-		p = MKID(expr->Identifier);
+		p = MKID_nr(expr->Identifier);
 		OUT("static asn_TYPE_member_t asn_MBR_%s[] = {\n", p);
 
 		elements = 0;
@@ -214,12 +217,13 @@
 	 */
 	emit_tag2member_map(arg, tag2el, tag2el_count, 0);
 
+	OUT("static asn_SEQUENCE_specifics_t asn_DEF_%s_specs = {\n",
+		MKID_nr(expr->Identifier));
 	p = MKID(expr->Identifier);
-	OUT("static asn_SEQUENCE_specifics_t asn_DEF_%s_specs = {\n", p);
 	INDENTED(
 		OUT("sizeof(struct %s),\n", p);
 		OUT("offsetof(struct %s, _asn_ctx),\n", p);
-		OUT("asn_DEF_%s_tag2el,\n", p);
+		OUT("asn_DEF_%s_tag2el,\n", MKID_nr(expr->Identifier));
 		OUT("%d,\t/* Count of tags in the map */\n", tag2el_count);
 		OUT("%d,\t/* Start extensions */\n",
 			ext_start);
@@ -256,26 +260,26 @@
 	OUT(" * Method of determining the components presence\n");
 	OUT(" */\n");
 	mcount = 0;
-	OUT("typedef enum %s_PR {\n", MKID(expr->Identifier));
+	OUT("typedef enum "); out_identifiers_chain(arg, 0); OUT("_PR {\n");
 	TQ_FOR(v, &(expr->members), next) {
 		if(v->expr_type == A1TC_EXTENSIBLE) continue;
 		INDENTED(
-			id = MKID(expr->Identifier);
-			OUT("%s_PR_", id);
-			id = MKID(v->Identifier);
+			out_identifiers_chain(arg, 0);
+			OUT("_PR_");
+			id = MKID_nr(v->Identifier);
 			OUT("%s,\t/* Member %s is present */\n",
 				id, id)
 		);
 		mcount++;
 	}
-	id = MKID(expr->Identifier);
-	OUT("} %s_PR;\n", id);
+	OUT("} "); out_identifiers_chain(arg, 0); OUT("_PR;\n");
 
 	REDIR(OT_TYPE_DECLS);
 
 	if(arg->embed) {
-		OUT("struct %s {\n", id);
+		OUT("struct "); out_identifiers_chain(arg, 1); OUT(" {\n");
 	} else {
+		id = MKID(expr->Identifier);
 		OUT("typedef struct %s {\n", id);
 	}
 
@@ -290,7 +294,7 @@
 	}
 
 	INDENTED(
-		id = MKID(expr->Identifier);
+		id = MKID_nr(expr->Identifier);
 		OUT("\n");
 		OUT("/* Presence bitmask: ASN_SET_ISPRESENT(p%s, %s_PR_x) */\n",
 			id, id);
@@ -350,8 +354,8 @@
 	if(expr_elements_count(arg, expr)) {
 		int comp_mode = 0;	/* {root,ext=1,root,root,...} */
 
-		p = MKID(expr->Identifier);
-		OUT("static asn_TYPE_member_t asn_MBR_%s[] = {\n", p);
+		OUT("static asn_TYPE_member_t asn_MBR_%s[] = {\n",
+			MKID_nr(expr->Identifier));
 	
 		elements = 0;
 		INDENTED(TQ_FOR(v, &(expr->members), next) {
@@ -385,8 +389,9 @@
 	/*
 	 * Emit a map of mandatory elements.
 	 */
+	OUT("static uint8_t asn_DEF_%s_mmap",
+		MKID_nr(expr->Identifier));
 	p = MKID(expr->Identifier);
-	OUT("static uint8_t asn_DEF_%s_mmap", p);
 	OUT("[(%d + (8 * sizeof(unsigned int)) - 1) / 8]", elements);
 	OUT(" = {\n", p);
 	INDENTED(
@@ -415,11 +420,14 @@
 	OUT("\n");
 	OUT("};\n");
 
-	OUT("static asn_SET_specifics_t asn_DEF_%s_specs = {\n", p);
+	OUT("static asn_SET_specifics_t asn_DEF_%s_specs = {\n",
+		MKID_nr(expr->Identifier));
+	p = MKID(expr->Identifier);
 	INDENTED(
 		OUT("sizeof(struct %s),\n", p);
 		OUT("offsetof(struct %s, _asn_ctx),\n", p);
 		OUT("offsetof(struct %s, _presence_map),\n", p);
+		p = MKID_nr(expr->Identifier);
 		OUT("asn_DEF_%s_tag2el,\n", p);
 		OUT("%d,\t/* Count of tags in the map */\n", tag2el_count);
 		if(tag2el_cxer)
@@ -452,7 +460,7 @@
 	DEPENDENCIES;
 
 	if(arg->embed) {
-		OUT("struct %s {\n", MKID(expr->Identifier));
+		OUT("struct "); out_identifiers_chain(arg, 1); OUT(" {\n");
 	} else {
 		OUT("typedef struct %s {\n", MKID(expr->Identifier));
 	}
@@ -483,7 +491,7 @@
 		arg->embed--;
 		assert(arg->target->target == OT_TYPE_DECLS);
 	} else {
-		OUT("%s", asn1c_type_name(arg, memb, TNF_CTYPE));
+		OUT("%s", asn1c_type_name(arg, memb, TNF_CTYPE | TNF_CHECK));
 	}
 	OUT(") list;\n");
 	INDENT(-1);
@@ -545,8 +553,9 @@
 	 */
 	tv_mode = emit_tags_vectors(arg, expr, &tags_count, &all_tags_count);
 
+	OUT("static asn_SET_OF_specifics_t asn_DEF_%s_specs = {\n",
+			MKID_nr(expr->Identifier));
 	p = MKID(expr->Identifier);
-	OUT("static asn_SET_OF_specifics_t asn_DEF_%s_specs = {\n", p);
 	INDENTED(
 		OUT("sizeof(struct %s),\n", p);
 		OUT("offsetof(struct %s, _asn_ctx),\n", p);
@@ -578,36 +587,36 @@
 
 	REDIR(OT_DEPS);
 
-	id = MKID(expr->Identifier);
-	OUT("typedef enum %s_PR {\n", id);
+	OUT("typedef enum "); out_identifiers_chain(arg, 0); OUT("_PR {\n");
 	INDENTED(
-		OUT("%s_PR_NOTHING,\t"
-			"/* No components present */\n", id);
+		out_identifiers_chain(arg, 0);
+		OUT("_PR_NOTHING,\t/* No components present */\n");
 		TQ_FOR(v, &(expr->members), next) {
 			if(v->expr_type == A1TC_EXTENSIBLE) {
 				OUT("/* Extensions may appear below */\n");
 				continue;
 			}
-			id = MKID(expr->Identifier);
-			OUT("%s_PR_", id);
-			id = MKID(v->Identifier);
+			out_identifiers_chain(arg, 0);
+			OUT("_PR_");
+			id = MKID_nr(v->Identifier);
 			OUT("%s,\n", id, id);
 		}
 	);
-	id = MKID(expr->Identifier);
-	OUT("} %s_PR;\n", id);
+	OUT("} "); out_identifiers_chain(arg, 0); OUT("_PR;\n");
 
 	REDIR(OT_TYPE_DECLS);
 
 	if(arg->embed) {
-		OUT("struct %s {\n", id);
+		OUT("struct "); out_identifiers_chain(arg, 1); OUT(" {\n");
 	} else {
+		id = MKID(expr->Identifier);
 		OUT("typedef struct %s {\n", id);
 	}
 
 	INDENTED(
-		OUT("%s_PR present;\n", id);
-		OUT("union {\n", id);
+		out_identifiers_chain(arg, 0);
+		OUT("_PR present;\n");
+		OUT("union {\n");
 		TQ_FOR(v, &(expr->members), next) {
 			if(expr_better_indirect(arg, v))
 				v->marker.flags |= EM_INDIRECT;
@@ -690,14 +699,15 @@
 	 */
 	emit_tag2member_map(arg, tag2el, tag2el_count, 0);
 
+	OUT("static asn_CHOICE_specifics_t asn_DEF_%s_specs = {\n",
+		MKID_nr(expr->Identifier));
 	p = MKID(expr->Identifier);
-	OUT("static asn_CHOICE_specifics_t asn_DEF_%s_specs = {\n", p);
 	INDENTED(
 		OUT("sizeof(struct %s),\n", p);
 		OUT("offsetof(struct %s, _asn_ctx),\n", p);
 		OUT("offsetof(struct %s, present),\n", p);
 		OUT("sizeof(((struct %s *)0)->present),\n", p);
-		OUT("asn_DEF_%s_tag2el,\n", p);
+		OUT("asn_DEF_%s_tag2el,\n", MKID_nr(expr->Identifier));
 		OUT("%d,\t/* Count of tags in the map */\n", tag2el_count);
 		OUT("%d\t/* Whether extensible */\n",
 			check_if_extensible(expr));
@@ -784,13 +794,13 @@
 			 	tnfmt = TNF_RSAFE;
 				OUT("\n");
 				OUT("%s;\t/* Forward declaration */\n",
-					asn1c_type_name(arg, arg->expr, tnfmt));
+					asn1c_type_name(arg, arg->expr, tnfmt | TNF_CHECK));
 			}
 		}
 
 		REDIR(OT_TYPE_DECLS);
 
-		OUT("%s\t", asn1c_type_name(arg, arg->expr, tnfmt));
+		OUT("%s\t", asn1c_type_name(arg, arg->expr, tnfmt | TNF_CHECK));
 		OUT("%s", expr->marker.flags?"*":" ");
 		OUT("%s", MKID(expr->Identifier));
 		if((expr->marker.flags & EM_DEFAULT) == EM_DEFAULT)
@@ -808,7 +818,7 @@
 
 	REDIR(OT_TYPE_DECLS);
 
-	OUT("typedef %s\t", asn1c_type_name(arg, arg->expr, TNF_CTYPE));
+	OUT("typedef %s\t", asn1c_type_name(arg, arg->expr, TNF_CTYPE | TNF_CHECK));
 	OUT("%s", expr->marker.flags?"*":" ");
 	OUT("%s_t", MKID(expr->Identifier));
 
@@ -824,9 +834,8 @@
 		REDIR(OT_FUNC_DECLS);
 		type_name = asn1c_type_name(arg, expr, TNF_SAFE);
 		OUT("/* This type is equivalent to %s */\n", type_name);
-		p = MKID(expr->Identifier);
 		if(HIDE_INNER_DEFS) OUT("/* ");
-		OUT("#define\tasn_DEF_%s\t", p);
+		OUT("#define\tasn_DEF_%s\t", MKID_nr(expr->Identifier));
 		type_name = asn1c_type_name(arg, expr, TNF_SAFE);
 		OUT("asn_DEF_%s\n", type_name);
 		if(HIDE_INNER_DEFS)
@@ -987,7 +996,7 @@
 
 	REDIR(OT_FUNC_DECLS);
 
-	p = MKID(expr->Identifier);
+	p = MKID_nr(expr->Identifier);
 	if(HIDE_INNER_DEFS) OUT("/* ");
 	OUT("extern asn_TYPE_descriptor_t asn_DEF_%s;", p);
 	if(HIDE_INNER_DEFS) OUT(" // (Use -fall-defs-global to expose) */");
@@ -1237,7 +1246,7 @@
 	asn1p_expr_t *expr = arg->expr;
 
 	OUT("static asn_TYPE_tag2member_t asn_DEF_%s_tag2el%s[] = {\n",
-		MKID(expr->Identifier), opt_modifier?opt_modifier:"");
+		MKID_nr(expr->Identifier), opt_modifier?opt_modifier:"");
 	if(tag2el_count) {
 		int i;
 		for(i = 0; i < tag2el_count; i++) {
@@ -1303,7 +1312,7 @@
 
 #define	EMIT_TAGS_TABLE(name, tags, tags_count)	do {			\
 		OUT("static ber_tlv_tag_t asn_DEF_%s%s_tags[] = {\n",	\
-			MKID(expr->Identifier), name);			\
+			MKID_nr(expr->Identifier), name);		\
 		INDENT(+1);						\
 		/* Print the array of collected tags */			\
 		for(i = 0; i < tags_count; i++) {			\
@@ -1423,10 +1432,10 @@
 	if(C99_MODE) OUT(".type = ");
 	if(expr->_anonymous_type && (expr->expr_type & ASN_CONSTR_MASK)) {
 		OUT("(void *)&asn_DEF_%s_member,\n",
-			MKID(arg->expr->Identifier));
+			MKID_nr(arg->expr->Identifier));
 	} else if(expr->expr_type & ASN_CONSTR_MASK) {
 		OUT("(void *)&asn_DEF_%s,\n",
-			MKID(expr->Identifier));
+			MKID_nr(expr->Identifier));
 	} else {
 		OUT("(void *)&asn_DEF_%s,\n",
 			asn1c_type_name(arg, expr, TNF_SAFE));
@@ -1436,7 +1445,7 @@
 		if(arg->flags & A1C_NO_CONSTRAINTS) {
 			OUT("0,\t/* No check because of -fno-constraints */\n");
 		} else {
-			char *id = MKID(expr->Identifier);
+			char *id = MKID_nr(expr->Identifier);
 			if(expr->_anonymous_type
 					&& !strcmp(expr->Identifier, "member"))
 				id = asn1c_type_name(arg, expr, TNF_SAFE);
@@ -1460,7 +1469,7 @@
 	if(expr->_anonymous_type && !strcmp(expr->Identifier, "member"))
 		p = asn1c_type_name(arg, expr, TNF_SAFE);
 	else
-		p = MKID(expr->Identifier);
+		p = MKID_nr(expr->Identifier);
 	OUT("static int\n");
 	OUT("memb_%s_%d_constraint(asn_TYPE_descriptor_t *td, const void *sptr,\n", p, global_memb_unique);
 	INDENT(+1);
@@ -1487,10 +1496,11 @@
 emit_type_DEF(arg_t *arg, asn1p_expr_t *expr, enum tvm_compat tv_mode, int tags_count, int all_tags_count, int elements_count, enum etd_spec spec) {
 	char *p;
 
-	p = MKID(expr->Identifier);
 	if(HIDE_INNER_DEFS)
 		OUT("static /* Use -fall-defs-global to expose */\n");
-	OUT("asn_TYPE_descriptor_t asn_DEF_%s = {\n", p);
+	OUT("asn_TYPE_descriptor_t asn_DEF_%s = {\n",
+		MKID_nr(expr->Identifier));
+	p = MKID(expr->Identifier);
 	INDENT(+1);
 		OUT("\"%s\",\n", expr->_anonymous_type?"":expr->Identifier);
 		OUT("\"%s\",\n", expr->_anonymous_type?"":expr->Identifier);
@@ -1515,14 +1525,13 @@
 		}
 		OUT("%s_encode_xer,\n", p);
 
-		p = MKID(expr->Identifier);
-
 		if(expr->expr_type == ASN_CONSTR_CHOICE) {
 			OUT("CHOICE_outmost_tag,\n");
 		} else {
 			OUT("0,\t/* Use generic outmost tag fetcher */\n");
 		}
 
+		p = MKID_nr(expr->Identifier);
 		if(tags_count) {
 			OUT("asn_DEF_%s_tags,\n", p);
 			OUT("sizeof(asn_DEF_%s_tags)\n", p);
@@ -1627,3 +1636,32 @@
 		return 0;
 	}
 }
+
+static int
+out_identifiers_chain(arg_t *arg, int check_reserved_keywords) {
+	asn1p_expr_t *expr = arg->expr;
+	char *id;
+
+	assert(expr->Identifier);
+
+	if(arg->flags & A1C_DOUBLE_IDENTIFIERS
+	&& expr->parent_expr
+	&& expr->parent_expr->Identifier) {
+		arg_t tmparg = *arg;
+
+		tmparg.expr = expr->parent_expr;
+		tmparg.flags &= ~A1C_DOUBLE_IDENTIFIERS;
+		out_identifiers_chain(&tmparg, 0);
+
+		OUT("_");	/* a separator between id components */
+		/* Fall through */
+	}
+
+	if(check_reserved_keywords)
+		id = MKID(expr->Identifier);
+	else
+		id = MKID_nr(expr->Identifier);
+	OUT("%s", id);
+
+	return 0;
+}
diff --git a/libasn1compiler/asn1c_constraint.c b/libasn1compiler/asn1c_constraint.c
index 4746951..6391535 100644
--- a/libasn1compiler/asn1c_constraint.c
+++ b/libasn1compiler/asn1c_constraint.c
@@ -13,8 +13,6 @@
 static asn1p_expr_type_e _find_terminal_type(arg_t *arg);
 static int emit_range_comparison_code(arg_t *arg, asn1cnst_range_t *range, const char *varname, asn1c_integer_t natural_start, asn1c_integer_t natural_stop);
 
-#define	MKID(id)	asn1c_make_identifier(0, (id), 0)
-
 static int global_compile_mark;
 
 int
diff --git a/libasn1compiler/asn1c_misc.c b/libasn1compiler/asn1c_misc.c
index a1dbbd8..90377bf 100644
--- a/libasn1compiler/asn1c_misc.c
+++ b/libasn1compiler/asn1c_misc.c
@@ -4,16 +4,34 @@
 #include <asn1fix_export.h>
 
 /*
+ * Checks that the given string is not a reserved C/C++ keyword.
+ */
+static char *res_kwd[] = {
+	"char", "int", "long",
+	"float", "double",
+	"struct", "typedef", "class" };
+static int
+reserved_keyword(const char *str) {
+	int i;
+	for(i = 0 ; i < sizeof(res_kwd)/sizeof(res_kwd[0]); i++) {
+		if(strcmp(str, res_kwd[i]) == 0)
+			return 1;
+	}
+	return 0;
+}
+
+/*
  * Construct identifier from multiple parts.
  * Convert unsafe characters to underscores.
  */
 char *
-asn1c_make_identifier(int unsafe_only_spaces, char *arg1, ...) {
+asn1c_make_identifier(enum ami_flags_e flags, char *arg1, ...) {
 	static char *storage;
 	static int storage_size;
 	int nodelimiter = 0;
 	va_list ap;
 	char *str;
+	char *nextstr;
 	int size;
 	char *p;
 
@@ -49,8 +67,9 @@
 	va_start(ap, arg1);
 	str = arg1;
 	p = storage;
-	for(str = arg1; str; str = va_arg(ap, char *)) {
+	for(str = arg1; str; str = nextstr) {
 		int subst_made = 0;
+		nextstr = va_arg(ap, char *);
 
 		if(str[0] == ' ' && str[1] == '\0') {
 			*p++ = ' ';
@@ -62,12 +81,23 @@
 			*p++ = '_';	/* Delimiter between tokens */
 		nodelimiter = 0;
 
+		/*
+		 * If it is a single argument, check that it does not clash
+		 * with C/C++ language keywords.
+		 */
+		if((flags & AMI_CHECK_RESERVED)
+		&& str == arg1 && !nextstr && reserved_keyword(str)) {
+			*p++ = toupper(*str++);
+			/* Fall through */
+		}
+
 		for(; *str; str++) {
 			if(isalnum(*str)) {
 				*p++ = *str;
 				subst_made = 0;
 			} else if(!subst_made++) {
-				if(unsafe_only_spaces && !isspace(*str)) {
+				if((flags & AMI_MASK_ONLY_SPACES)
+						&& !isspace(*str)) {
 					*p ++ = *str;
 				} else {
 					*p++ = '_';
@@ -87,6 +117,9 @@
 asn1c_type_name(arg_t *arg, asn1p_expr_t *expr, enum tnfmt _format) {
 	asn1p_expr_t *top_parent;
 	char *typename;
+	enum ami_flags_e ami_flags = (_format & TNF_CHECK)
+		? AMI_CHECK_RESERVED : 0;
+	_format &= ~TNF_CHECK;
 
 	/* Rewind to the topmost parent expression */
 	if((top_parent = expr->parent_expr))
@@ -180,13 +213,19 @@
 	switch(_format) {
 	case TNF_UNMODIFIED:
 	case TNF_INCLUDE:
-		return asn1c_make_identifier(1, typename, 0);
+		assert(ami_flags == 0);	/* (TNF_INCLUDE | TNF_CHECK)?! */
+		ami_flags |= AMI_MASK_ONLY_SPACES;
+		return asn1c_make_identifier(ami_flags, typename, 0);
 	case TNF_SAFE:
-		return asn1c_make_identifier(0, typename, 0);
+		return asn1c_make_identifier(ami_flags, typename, 0);
 	case TNF_CTYPE:
-		return asn1c_make_identifier(0, typename, "t", 0);
+		return asn1c_make_identifier(ami_flags, typename, "t", 0);
 	case TNF_RSAFE:
-		return asn1c_make_identifier(0, "struct", " ", typename, 0);
+		return asn1c_make_identifier(ami_flags, "struct", " ", typename, 0);
+	case TNF_NORCHECK:
+	case TNF_CHECK:
+		assert(_format != TNF_NORCHECK);
+		assert(_format != TNF_CHECK);
 	}
 
 	assert(!"unreachable");
diff --git a/libasn1compiler/asn1c_misc.h b/libasn1compiler/asn1c_misc.h
index 325892a..c653fa8 100644
--- a/libasn1compiler/asn1c_misc.h
+++ b/libasn1compiler/asn1c_misc.h
@@ -6,17 +6,23 @@
  * The function will concatenate the names and replace unsafe characters
  * with safe ones.
  */
-char *asn1c_make_identifier(int unsafe_only_spaces, char *arg1, ...);
+enum ami_flags_e {
+  AMI_MASK_ONLY_SPACES	= 1,	/* Mask only spaces, everything else's safe */
+  AMI_CHECK_RESERVED	= 2,	/* Check against reserved keywords */
+};
+char *asn1c_make_identifier(enum ami_flags_e, char *arg1, ...);
 
 /*
  * Return the type name of the specified expression.
  */
 enum tnfmt {
-	TNF_UNMODIFIED,		/* Return unmodified type name */
-	TNF_INCLUDE,		/* Format for #include <> */
-	TNF_CTYPE,		/* Format as normal C-ish type (append "_t") */
-	TNF_SAFE,		/* Replace unsafe characters with _ */
-	TNF_RSAFE,		/* Recursion-safe C type format */
+	TNF_NORCHECK	= 0x00,
+	TNF_CHECK	= 0x01,
+	TNF_UNMODIFIED	= 0x10,	/* Return unmodified type name */
+	TNF_INCLUDE	= 0x20,	/* Format for #include <> */
+	TNF_CTYPE	= 0x30,	/* Format as normal C-ish type (append "_t") */
+	TNF_SAFE	= 0x40, /* Replace unsafe characters with _ */
+	TNF_RSAFE	= 0x50,	/* Recursion-safe C type format */
 };
 char *asn1c_type_name(arg_t *arg, asn1p_expr_t *expr, enum tnfmt _format);
 
diff --git a/libasn1compiler/asn1compiler.h b/libasn1compiler/asn1compiler.h
index bd309e4..817e06c 100644
--- a/libasn1compiler/asn1compiler.h
+++ b/libasn1compiler/asn1compiler.h
@@ -39,6 +39,10 @@
 	 * Do not generate constraint checking code.
 	 */
 	A1C_NO_CONSTRAINTS	= 0x0080,
+	/*
+	 * Generate type_id_PR_member things identifiers of id_PR_member.
+	 */
+	A1C_DOUBLE_IDENTIFIERS	= 0x0100,
 };
 
 /*