distinction between an optional member and a member encoded with a pointer

diff --git a/libasn1compiler/asn1c_C.c b/libasn1compiler/asn1c_C.c
index 4d9390c..8755c2a 100644
--- a/libasn1compiler/asn1c_C.c
+++ b/libasn1compiler/asn1c_C.c
@@ -26,6 +26,7 @@
 static int asn1c_lang_C_type_SEx_OF_def(arg_t *arg, int seq_of);
 static int _print_tag(arg_t *arg, struct asn1p_type_tag_s *tag_p);
 static int check_if_extensible(asn1p_expr_t *expr);
+static int expr_better_indirect(arg_t *arg, asn1p_expr_t *expr);
 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_tags_vector(arg_t *arg, asn1p_expr_t *expr, int *tags_impl_skip, int choice_mode);
@@ -149,8 +150,9 @@
 		if(v->expr_type == A1TC_EXTENSIBLE) {
 			if(comp_mode < 3) comp_mode++;
 		}
-		if(comp_mode == 1 && !v->marker)
-			v->marker = EM_OPTIONAL;
+		if(comp_mode == 1
+		|| expr_better_indirect(arg, v))
+			v->marker |= EM_INDIRECT;
 		EMBED(v);
 	}
 
@@ -289,8 +291,9 @@
 		if(v->expr_type == A1TC_EXTENSIBLE) {
 			if(comp_mode < 3) comp_mode++;
 		}
-		if(comp_mode == 1 && !v->marker)
-			v->marker = EM_OPTIONAL;
+		if(comp_mode == 1
+		|| expr_better_indirect(arg, v))
+			v->marker |= EM_INDIRECT;
 		EMBED(v);
 	}
 
@@ -345,15 +348,15 @@
 
 	elements = 0;
 	INDENTED(TQ_FOR(v, &(expr->members), next) {
-		if(v->expr_type != A1TC_EXTENSIBLE) {
-			if(comp_mode == 1)
-				v->marker = EM_OPTIONAL;
-		} else {
+		if(v->expr_type == A1TC_EXTENSIBLE) {
 			if(comp_mode < 3) comp_mode++;
-			continue;
+		} else {
+			if(comp_mode == 1
+			|| expr_better_indirect(arg, v))
+				v->marker |= EM_INDIRECT;
+			elements++;
+			emit_member_table(arg, v);
 		}
-		elements++;
-		emit_member_table(arg, v);
 	});
 	OUT("};\n");
 
@@ -386,7 +389,9 @@
 			} else if(el) {
 				OUT(" | ");
 			}
-			OUT("(%d << %d)", v->marker?0:1, 7 - (el % 8));
+			OUT("(%d << %d)",
+				v->marker?0:1,
+				7 - (el % 8));
 			if(el && (el % 8) == 0)
 				delimit = 1;
 			el++;
@@ -573,6 +578,8 @@
 		OUT("%s_PR present;\n", id);
 		OUT("union {\n", id);
 		TQ_FOR(v, &(expr->members), next) {
+			if(expr_better_indirect(arg, v))
+				v->marker |= EM_INDIRECT;
 			EMBED(v);
 		}
 		if(UNNAMED_UNIONS)	OUT("};\n");
@@ -621,15 +628,15 @@
 
 	elements = 0;
 	INDENTED(TQ_FOR(v, &(expr->members), next) {
-		if(v->expr_type != A1TC_EXTENSIBLE) {
-			if(comp_mode == 1)
-				v->marker = EM_OPTIONAL;
-		} else {
+		if(v->expr_type == A1TC_EXTENSIBLE) {
 			if(comp_mode < 3) comp_mode++;
-			continue;
+		} else {
+			if(comp_mode == 1
+			|| expr_better_indirect(arg, v))
+				v->marker |= EM_INDIRECT;
+			elements++;
+			emit_member_table(arg, v);
 		}
-		elements++;
-		emit_member_table(arg, v);
 	});
 	OUT("};\n");
 
@@ -731,8 +738,10 @@
 			expr->marker?TNF_RSAFE:TNF_CTYPE));
 		OUT("%s", expr->marker?"*":" ");
 		OUT("%s", MKID(expr->Identifier));
-		if(expr->marker) OUT("\t/* %s */",
-			(expr->marker==EM_OPTIONAL)?"OPTIONAL":"DEFAULT");
+		if((expr->marker & EM_DEFAULT) == EM_DEFAULT)
+			OUT("\t/* DEFAULT */");
+		else if((expr->marker & EM_OPTIONAL) == EM_OPTIONAL)
+			OUT("\t/* OPTIONAL */");
 
 		REDIR(OT_TYPE_DECLS);
 		return 0;
@@ -1195,7 +1204,8 @@
 	char *p;
 
 	OUT("{ ");
-	if(expr->marker) {
+	OUT("%s, ", expr->marker?"ATF_POINTER":"ATF_NOFLAGS");
+	if((expr->marker & EM_OPTIONAL) == EM_OPTIONAL) {
 		asn1p_expr_t *tv;
 		int opts = 0;
 		for(tv = expr; tv && tv->marker;
@@ -1378,3 +1388,30 @@
 
 	return 0;
 }
+
+/*
+ * Check if it is better to make this type indirectly accessed via
+ * a pointer.
+ * This may be the case for the following recursive definition:
+ * Type ::= CHOICE { member Type };
+ */
+static int
+expr_better_indirect(arg_t *arg, asn1p_expr_t *expr) {
+	asn1p_expr_t *top_parent;
+	asn1p_expr_t *terminal;
+
+	if(expr->expr_type != A1TC_REFERENCE)
+		return 0;
+
+	/* Rewind to the topmost parent expression */
+	if((top_parent = expr->parent_expr)) {
+		while(top_parent->parent_expr)
+			top_parent = top_parent->parent_expr;
+	} else {
+		return 0;
+	}
+
+	terminal = asn1f_find_terminal_type_ex(arg->asn, arg->mod, expr);
+
+	return (terminal == top_parent);
+}