new constraints model


git-svn-id: https://asn1c.svn.sourceforge.net/svnroot/asn1c/trunk@163 59561ff5-6e30-0410-9f3c-9617f08c8826
diff --git a/skeletons/BIT_STRING.c b/skeletons/BIT_STRING.c
index 7e576a1..df11c19 100644
--- a/skeletons/BIT_STRING.c
+++ b/skeletons/BIT_STRING.c
@@ -23,6 +23,7 @@
 	  / sizeof(asn1_DEF_BIT_STRING_tags[0]),
 	1,	/* Single UNIVERSAL tag may be implicitly overriden */
 	-1,	/* Both ways are fine */
+	0, 0,	/* No members */
 	(void *)-1	/* Special indicator that this is a BIT STRING */
 };
 
diff --git a/skeletons/BMPString.c b/skeletons/BMPString.c
index d914168..6b3ceeb 100644
--- a/skeletons/BMPString.c
+++ b/skeletons/BMPString.c
@@ -23,6 +23,7 @@
 	  / sizeof(asn1_DEF_BMPString_tags[0]),
 	1,	/* Single UNIVERSAL tag may be implicitly overriden */
 	-1,	/* Both ways are fine */
+	0, 0,	/* No members */
 	0	/* No specifics */
 };
 
diff --git a/skeletons/BOOLEAN.c b/skeletons/BOOLEAN.c
index 4f9b324..da38772 100644
--- a/skeletons/BOOLEAN.c
+++ b/skeletons/BOOLEAN.c
@@ -22,6 +22,7 @@
 	sizeof(asn1_DEF_BOOLEAN_tags)/sizeof(asn1_DEF_BOOLEAN_tags[0]),
 	1,	/* Single UNIVERSAL tag may be implicitly overriden */
 	0,	/* Always in primitive form */
+	0, 0,	/* No members */
 	0	/* No specifics */
 };
 
diff --git a/skeletons/ENUMERATED.c b/skeletons/ENUMERATED.c
index 3fff368..12350ef 100644
--- a/skeletons/ENUMERATED.c
+++ b/skeletons/ENUMERATED.c
@@ -22,6 +22,7 @@
 	sizeof(asn1_DEF_ENUMERATED_tags)/sizeof(asn1_DEF_ENUMERATED_tags[0]),
 	1,	/* Single UNIVERSAL tag may be implicitly overriden */
 	0,	/* Primitive */
+	0, 0,	/* No members */
 	0	/* No specifics */
 };
 
diff --git a/skeletons/GeneralString.c b/skeletons/GeneralString.c
index 6bc7e47..db3b87d 100644
--- a/skeletons/GeneralString.c
+++ b/skeletons/GeneralString.c
@@ -23,6 +23,7 @@
 	  / sizeof(asn1_DEF_GeneralString_tags[0]),
 	1,	/* Single UNIVERSAL tag may be implicitly overriden */
 	-1,	/* Both ways are fine */
+	0, 0,	/* No members */
 	0	/* No specifics */
 };
 
diff --git a/skeletons/GeneralizedTime.c b/skeletons/GeneralizedTime.c
index 4d1b390..25f2bb6 100644
--- a/skeletons/GeneralizedTime.c
+++ b/skeletons/GeneralizedTime.c
@@ -88,6 +88,7 @@
 	  / sizeof(asn1_DEF_GeneralizedTime_tags[0]),
 	1,	/* Single UNIVERSAL tag may be implicitly overriden */
 	-1,	/* Both ways are fine */
+	0, 0,	/* No members */
 	0	/* No specifics */
 };
 
diff --git a/skeletons/GraphicString.c b/skeletons/GraphicString.c
index 412f3c7..bd93146 100644
--- a/skeletons/GraphicString.c
+++ b/skeletons/GraphicString.c
@@ -23,6 +23,7 @@
 	  / sizeof(asn1_DEF_GraphicString_tags[0]),
 	1,	/* Single UNIVERSAL tag may be implicitly overriden */
 	-1,	/* Both ways are fine */
+	0, 0,	/* No members */
 	0	/* No specifics */
 };
 
diff --git a/skeletons/IA5String.c b/skeletons/IA5String.c
index c520bb2..a44a9d0 100644
--- a/skeletons/IA5String.c
+++ b/skeletons/IA5String.c
@@ -23,6 +23,7 @@
 	  / sizeof(asn1_DEF_IA5String_tags[0]),
 	1,	/* Single UNIVERSAL tag may be implicitly overriden */
 	-1,	/* Both ways are fine */
+	0, 0,	/* No members */
 	0	/* No specifics */
 };
 
diff --git a/skeletons/INTEGER.c b/skeletons/INTEGER.c
index 9cf146e..0c7a81a 100644
--- a/skeletons/INTEGER.c
+++ b/skeletons/INTEGER.c
@@ -24,6 +24,7 @@
 	sizeof(asn1_DEF_INTEGER_tags)/sizeof(asn1_DEF_INTEGER_tags[0]),
 	1,	/* Single UNIVERSAL tag may be implicitly overriden */
 	0,	/* Always in primitive form */
+	0, 0,	/* No members */
 	0	/* No specifics */
 };
 
diff --git a/skeletons/ISO646String.c b/skeletons/ISO646String.c
index 2df623c..a86d0ce 100644
--- a/skeletons/ISO646String.c
+++ b/skeletons/ISO646String.c
@@ -23,6 +23,7 @@
 	  / sizeof(asn1_DEF_ISO646String_tags[0]),
 	1,	/* Single UNIVERSAL tag may be implicitly overriden */
 	-1,	/* Both ways are fine */
+	0, 0,	/* No members */
 	0	/* No specifics */
 };
 
diff --git a/skeletons/NULL.c b/skeletons/NULL.c
index 4ea0669..d71d90d 100644
--- a/skeletons/NULL.c
+++ b/skeletons/NULL.c
@@ -23,6 +23,7 @@
 	sizeof(asn1_DEF_NULL_tags)/sizeof(asn1_DEF_NULL_tags[0]),
 	1,	/* Single UNIVERSAL tag may be implicitly overriden */
 	0,	/* Always in primitive form */
+	0, 0,	/* No members */
 	0	/* No specifics */
 };
 
diff --git a/skeletons/NativeEnumerated.c b/skeletons/NativeEnumerated.c
index bfb2bff..139a602 100644
--- a/skeletons/NativeEnumerated.c
+++ b/skeletons/NativeEnumerated.c
@@ -29,5 +29,7 @@
 	sizeof(asn1_DEF_NativeEnumerated_tags)/sizeof(asn1_DEF_NativeEnumerated_tags[0]),
 	1,	/* Single UNIVERSAL tag may be implicitly overriden */
 	0,	/* Always in primitive form */
+	0, 0,	/* No members */
 	0	/* No specifics */
 };
+
diff --git a/skeletons/NativeInteger.c b/skeletons/NativeInteger.c
index ca29049..759fe27 100644
--- a/skeletons/NativeInteger.c
+++ b/skeletons/NativeInteger.c
@@ -31,6 +31,7 @@
 	sizeof(asn1_DEF_NativeInteger_tags)/sizeof(asn1_DEF_NativeInteger_tags[0]),
 	1,	/* Single UNIVERSAL tag may be implicitly overriden */
 	0,	/* Always in primitive form */
+	0, 0,	/* No members */
 	0	/* No specifics */
 };
 
diff --git a/skeletons/NumericString.c b/skeletons/NumericString.c
index a8d4ed8..6c8729f 100644
--- a/skeletons/NumericString.c
+++ b/skeletons/NumericString.c
@@ -23,6 +23,7 @@
 	  / sizeof(asn1_DEF_NumericString_tags[0]),
 	1,	/* Single UNIVERSAL tag may be implicitly overriden */
 	-1,	/* Both ways are fine */
+	0, 0,	/* No members */
 	0	/* No specifics */
 };
 
diff --git a/skeletons/OBJECT_IDENTIFIER.c b/skeletons/OBJECT_IDENTIFIER.c
index 89e2e32..063ae97 100644
--- a/skeletons/OBJECT_IDENTIFIER.c
+++ b/skeletons/OBJECT_IDENTIFIER.c
@@ -26,6 +26,7 @@
 	    / sizeof(asn1_DEF_OBJECT_IDENTIFIER_tags[0]),
 	1,	/* Single UNIVERSAL tag may be implicitly overriden */
 	0,	/* Always in primitive form */
+	0, 0,	/* No members */
 	0	/* No specifics */
 };
 
diff --git a/skeletons/OCTET_STRING.c b/skeletons/OCTET_STRING.c
index e0a7bb2..8ea360d 100644
--- a/skeletons/OCTET_STRING.c
+++ b/skeletons/OCTET_STRING.c
@@ -25,6 +25,7 @@
 	  / sizeof(asn1_DEF_OCTET_STRING_tags[0]),
 	1,	/* Single UNIVERSAL tag may be implicitly overriden */
 	-1,	/* Both ways are fine (primitive and constructed) */
+	0, 0,	/* No members */
 	0	/* No specifics */
 };
 
diff --git a/skeletons/ObjectDescriptor.c b/skeletons/ObjectDescriptor.c
index db699ca..3a03b97 100644
--- a/skeletons/ObjectDescriptor.c
+++ b/skeletons/ObjectDescriptor.c
@@ -23,6 +23,7 @@
 	  / sizeof(asn1_DEF_ObjectDescriptor_tags[0]),
 	1,	/* Single UNIVERSAL tag may be implicitly overriden */
 	-1,	/* Both ways are fine */
+	0, 0,	/* No members */
 	0	/* No specifics */
 };
 
diff --git a/skeletons/PrintableString.c b/skeletons/PrintableString.c
index f894d82..8f67edd 100644
--- a/skeletons/PrintableString.c
+++ b/skeletons/PrintableString.c
@@ -23,6 +23,7 @@
 	  / sizeof(asn1_DEF_PrintableString_tags[0]),
 	1,	/* Single UNIVERSAL tag may be implicitly overriden */
 	-1,	/* Both ways are fine */
+	0, 0,	/* No members */
 	0	/* No specifics */
 };
 
diff --git a/skeletons/RELATIVE-OID.c b/skeletons/RELATIVE-OID.c
index eaf98b1..3273ace 100644
--- a/skeletons/RELATIVE-OID.c
+++ b/skeletons/RELATIVE-OID.c
@@ -26,6 +26,7 @@
 	    / sizeof(asn1_DEF_RELATIVE_OID_tags[0]),
 	1,	/* Single UNIVERSAL tag may be implicitly overriden */
 	0,	/* Always in primitive form */
+	0, 0,	/* No members */
 	0	/* No specifics */
 };
 
diff --git a/skeletons/T61String.c b/skeletons/T61String.c
index 2ba5d32..2815298 100644
--- a/skeletons/T61String.c
+++ b/skeletons/T61String.c
@@ -23,6 +23,7 @@
 	  / sizeof(asn1_DEF_T61String_tags[0]),
 	1,	/* Single UNIVERSAL tag may be implicitly overriden */
 	-1,	/* Both ways are fine */
+	0, 0,	/* No members */
 	0	/* No specifics */
 };
 
diff --git a/skeletons/TeletexString.c b/skeletons/TeletexString.c
index dafbd58..3c20e2f 100644
--- a/skeletons/TeletexString.c
+++ b/skeletons/TeletexString.c
@@ -23,6 +23,7 @@
 	  / sizeof(asn1_DEF_TeletexString_tags[0]),
 	1,	/* Single UNIVERSAL tag may be implicitly overriden */
 	-1,	/* Both ways are fine */
+	0, 0,	/* No members */
 	0	/* No specifics */
 };
 
diff --git a/skeletons/UTCTime.c b/skeletons/UTCTime.c
index 7d97117..8b7972c 100644
--- a/skeletons/UTCTime.c
+++ b/skeletons/UTCTime.c
@@ -29,6 +29,7 @@
 	  / sizeof(asn1_DEF_UTCTime_tags[0]),
 	1,	/* Single UNIVERSAL tag may be implicitly overriden */
 	-1,	/* Both ways are fine */
+	0, 0,	/* No members */
 	0	/* No specifics */
 };
 
diff --git a/skeletons/UTF8String.c b/skeletons/UTF8String.c
index 06e1559..aab4a2e 100644
--- a/skeletons/UTF8String.c
+++ b/skeletons/UTF8String.c
@@ -23,6 +23,7 @@
 	  / sizeof(asn1_DEF_UTF8String_tags[0]),
 	1,	/* Single UNIVERSAL tag may be implicitly overriden */
 	-1,	/* Both ways are fine */
+	0, 0,	/* No members */
 	0	/* No specifics */
 };
 
diff --git a/skeletons/UniversalString.c b/skeletons/UniversalString.c
index 241fe67..628ed0c 100644
--- a/skeletons/UniversalString.c
+++ b/skeletons/UniversalString.c
@@ -23,6 +23,7 @@
 	  / sizeof(asn1_DEF_UniversalString_tags[0]),
 	1,	/* Single UNIVERSAL tag may be implicitly overriden */
 	-1,	/* Both ways are fine */
+	0, 0,	/* No members */
 	0	/* No specifics */
 };
 
diff --git a/skeletons/VideotexString.c b/skeletons/VideotexString.c
index d9293be..df21b14 100644
--- a/skeletons/VideotexString.c
+++ b/skeletons/VideotexString.c
@@ -23,6 +23,7 @@
 	  / sizeof(asn1_DEF_VideotexString_tags[0]),
 	1,	/* Single UNIVERSAL tag may be implicitly overriden */
 	-1,	/* Both ways are fine */
+	0, 0,	/* No members */
 	0	/* No specifics */
 };
 
diff --git a/skeletons/VisibleString.c b/skeletons/VisibleString.c
index 4033a17..aa9c99b 100644
--- a/skeletons/VisibleString.c
+++ b/skeletons/VisibleString.c
@@ -23,6 +23,7 @@
 	  / sizeof(asn1_DEF_VisibleString_tags[0]),
 	1,	/* Single UNIVERSAL tag may be implicitly overriden */
 	-1,	/* Both ways are fine */
+	0, 0,	/* No members */
 	0	/* No specifics */
 };
 
diff --git a/skeletons/constr_CHOICE.c b/skeletons/constr_CHOICE.c
index 4aaad23..3fbf194 100644
--- a/skeletons/constr_CHOICE.c
+++ b/skeletons/constr_CHOICE.c
@@ -93,13 +93,13 @@
  * The decoder of the CHOICE type.
  */
 ber_dec_rval_t
-CHOICE_decode_ber(asn1_TYPE_descriptor_t *sd,
+CHOICE_decode_ber(asn1_TYPE_descriptor_t *td,
 	void **struct_ptr, void *ptr, size_t size, int tag_mode) {
 	/*
 	 * Bring closer parts of structure description.
 	 */
-	asn1_CHOICE_specifics_t *specs = (asn1_CHOICE_specifics_t *)sd->specifics;
-	asn1_CHOICE_element_t *elements = specs->elements;
+	asn1_CHOICE_specifics_t *specs = (asn1_CHOICE_specifics_t *)td->specifics;
+	asn1_TYPE_member_t *elements = td->elements;
 
 	/*
 	 * Parts of the structure being constructed.
@@ -114,7 +114,7 @@
 
 	ssize_t consumed_myself = 0;	/* Consumed bytes from ptr */
 
-	ASN_DEBUG("Decoding %s as CHOICE", sd->name);
+	ASN_DEBUG("Decoding %s as CHOICE", td->name);
 	
 	/*
 	 * Create the target structure if it is not present already.
@@ -142,12 +142,12 @@
 		 * perfectly fits our expectations.
 		 */
 
-		if(tag_mode || sd->tags_count) {
-			rval = ber_check_tags(sd, ctx, ptr, size,
+		if(tag_mode || td->tags_count) {
+			rval = ber_check_tags(td, ctx, ptr, size,
 				tag_mode, &ctx->left, 0);
 			if(rval.code != RC_OK) {
 				ASN_DEBUG("%s tagging check failed: %d",
-					sd->name, rval.code);
+					td->name, rval.code);
 				consumed_myself += rval.consumed;
 				RETURN(rval.code);
 			}
@@ -172,7 +172,7 @@
 		 * Fetch the T from TLV.
 		 */
 		tag_len = ber_fetch_tag(ptr, LEFT, &tlv_tag);
-		ASN_DEBUG("In %s CHOICE tag length %d", sd->name, (int)tag_len);
+		ASN_DEBUG("In %s CHOICE tag length %d", td->name, (int)tag_len);
 		switch(tag_len) {
 		case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE);
 			/* Fall through */
@@ -197,7 +197,7 @@
 			} else if(specs->extensible == 0) {
 				ASN_DEBUG("Unexpected tag %s "
 					"in non-extensible CHOICE %s",
-					ber_tlv_tag_string(tlv_tag), sd->name);
+					ber_tlv_tag_string(tlv_tag), td->name);
 				RETURN(RC_FAIL);
 			} else {
 				/* Skip this tag */
@@ -227,7 +227,7 @@
 		 * Read in the element.
 		 */
 	    do {
-		asn1_CHOICE_element_t *elm;	/* CHOICE's element */
+		asn1_TYPE_member_t *elm;/* CHOICE's element */
 		void *memb_ptr;		/* Pointer to the member */
 		void **memb_ptr2;	/* Pointer to that pointer */
 
@@ -252,6 +252,9 @@
 		/*
 		 * Invoke the member fetch routine according to member's type
 		 */
+		printf("elm->name = %s\n", elm->name);
+		printf("elm->td = %p\n", elm->type);
+		printf("elm->td->name = %s\n", elm->type->name);
 		rval = elm->type->ber_decoder(elm->type,
 				memb_ptr2, ptr, LEFT,
 				elm->tag_mode);
@@ -278,8 +281,8 @@
 		/* Fall through */
 	case 3:
 		ASN_DEBUG("CHOICE %s Leftover: %ld, size = %ld, tm=%d, tc=%d",
-			sd->name, (long)ctx->left, (long)size,
-			tag_mode, sd->tags_count);
+			td->name, (long)ctx->left, (long)size,
+			tag_mode, td->tags_count);
 
 		if(ctx->left > 0) {
 			/*
@@ -290,7 +293,7 @@
 		}
 
 		if(ctx->left == -1
-		&& !(tag_mode || sd->tags_count)) {
+		&& !(tag_mode || td->tags_count)) {
 			/*
 			 * This is an untagged CHOICE.
 			 * It doesn't contain nothing
@@ -331,7 +334,7 @@
 				}
 			} else {
 				ASN_DEBUG("Unexpected continuation in %s",
-					sd->name);
+					td->name);
 				RETURN(RC_FAIL);
 			}
 
@@ -349,19 +352,19 @@
 }
 
 der_enc_rval_t
-CHOICE_encode_der(asn1_TYPE_descriptor_t *sd,
+CHOICE_encode_der(asn1_TYPE_descriptor_t *td,
 		void *struct_ptr,
 		int tag_mode, ber_tlv_tag_t tag,
 		asn_app_consume_bytes_f *cb, void *app_key) {
-	asn1_CHOICE_specifics_t *specs = (asn1_CHOICE_specifics_t *)sd->specifics;
-	asn1_CHOICE_element_t *elm;	/* CHOICE element */
+	asn1_CHOICE_specifics_t *specs = (asn1_CHOICE_specifics_t *)td->specifics;
+	asn1_TYPE_member_t *elm;	/* CHOICE element */
 	der_enc_rval_t erval;
 	void *memb_ptr;
 	size_t computed_size = 0;
 	int present;
 
 	ASN_DEBUG("%s %s as CHOICE",
-		cb?"Encoding":"Estimating", sd->name);
+		cb?"Encoding":"Estimating", td->name);
 
 	present = _fetch_present_idx(struct_ptr,
 		specs->pres_offset, specs->pres_size);
@@ -370,14 +373,14 @@
 	 * If the structure was not initialized, it cannot be encoded:
 	 * can't deduce what to encode in the choice type.
 	 */
-	if(present <= 0 || present > specs->elements_count) {
-		if(present == 0 && specs->elements_count == 0) {
+	if(present <= 0 || present > td->elements_count) {
+		if(present == 0 && td->elements_count == 0) {
 			/* The CHOICE is empty?! */
 			erval.encoded = 0;
 			return erval;
 		}
 		erval.encoded = -1;
-		erval.failed_type = sd;
+		erval.failed_type = td;
 		erval.structure_ptr = struct_ptr;
 		return erval;
 	}
@@ -385,7 +388,7 @@
 	/*
 	 * Seek over the present member of the structure.
 	 */
-	elm = &specs->elements[present-1];
+	elm = &td->elements[present-1];
 	if(elm->optional) {
 		memb_ptr = *(void **)((char *)struct_ptr + elm->memb_offset);
 		if(memb_ptr == 0) {
@@ -401,7 +404,7 @@
 	 * T ::= [2] EXPLICIT CHOICE { ... }
 	 * Then emit the appropriate tags.
 	 */
-	if(tag_mode == 1 || sd->tags_count) {
+	if(tag_mode == 1 || td->tags_count) {
 		/*
 		 * For this, we need to pre-compute the member.
 		 */
@@ -414,11 +417,11 @@
 			return erval;
 
 		/* Encode CHOICE with parent or my own tag */
-		ret = der_write_tags(sd, erval.encoded, tag_mode, tag,
+		ret = der_write_tags(td, erval.encoded, tag_mode, tag,
 			cb, app_key);
 		if(ret == -1) {
 			erval.encoded = -1;
-			erval.failed_type = sd;
+			erval.failed_type = td;
 			erval.structure_ptr = struct_ptr;
 			return erval;
 		}
@@ -454,8 +457,8 @@
 	 */
 	present = _fetch_present_idx(ptr, specs->pres_offset, specs->pres_size);
 
-	if(present > 0 || present <= specs->elements_count) {
-		asn1_CHOICE_element_t *elm = &specs->elements[present-1];
+	if(present > 0 || present <= td->elements_count) {
+		asn1_TYPE_member_t *elm = &td->elements[present-1];
 		const void *memb_ptr;
 
 		if(elm->optional) {
@@ -489,8 +492,8 @@
 	 * Figure out which CHOICE element is encoded.
 	 */
 	present = _fetch_present_idx(sptr, specs->pres_offset,specs->pres_size);
-	if(present > 0 && present <= specs->elements_count) {
-		asn1_CHOICE_element_t *elm = &specs->elements[present-1];
+	if(present > 0 && present <= td->elements_count) {
+		asn1_TYPE_member_t *elm = &td->elements[present-1];
 		const void *memb_ptr;
 
 		if(elm->optional) {
@@ -500,8 +503,19 @@
 			memb_ptr = (const void *)((const char *)sptr + elm->memb_offset);
 		}
 
-		return elm->type->check_constraints(elm->type, memb_ptr,
+		if(elm->memb_constraints) {
+			return elm->memb_constraints(elm->type, memb_ptr,
 				app_errlog, app_key);
+		} else {
+			int ret = elm->type->check_constraints(elm->type,
+					memb_ptr, app_errlog, app_key);
+			/*
+			 * Cannot inherit it eralier:
+			 * need to make sure we get the updated version.
+			 */
+			elm->memb_constraints = elm->type->check_constraints;
+			return ret;
+		}
 	} else {
 		_ASN_ERRLOG(app_errlog, app_key,
 			"%s: no CHOICE element given", td->name);
@@ -525,8 +539,8 @@
 	/*
 	 * Free that element.
 	 */
-	if(present > 0 && present <= specs->elements_count) {
-		asn1_CHOICE_element_t *elm = &specs->elements[present-1];
+	if(present > 0 && present <= td->elements_count) {
+		asn1_TYPE_member_t *elm = &td->elements[present-1];
 		const void *memb_ptr;
 
 		if(elm->optional) {
@@ -566,8 +580,8 @@
 	/*
 	 * Free that element.
 	 */
-	if(present > 0 && present <= specs->elements_count) {
-		asn1_CHOICE_element_t *elm = &specs->elements[present-1];
+	if(present > 0 && present <= td->elements_count) {
+		asn1_TYPE_member_t *elm = &td->elements[present-1];
 		void *memb_ptr;
 
 		if(elm->optional) {
diff --git a/skeletons/constr_CHOICE.h b/skeletons/constr_CHOICE.h
index 1308bd4..327bae2 100644
--- a/skeletons/constr_CHOICE.h
+++ b/skeletons/constr_CHOICE.h
@@ -7,18 +7,6 @@
 
 #include <constr_TYPE.h>
 
-/*
- * A single element of the CHOICE type.
- */
-typedef struct asn1_CHOICE_element_s {
-	int memb_offset;		/* Offset of the element */
-	int optional;			/* Whether the element is optional */
-	ber_tlv_tag_t tag;		/* Outmost (most immediate) tag */
-	int tag_mode;		/* IMPLICIT/no/EXPLICIT tag at current level */
-	asn1_TYPE_descriptor_t *type;	/* Member type descriptor */
-	char *name;			/* ASN.1 identifier of the element */
-} asn1_CHOICE_element_t;
-
 typedef struct asn1_CHOICE_specifics_s {
 	/*
 	 * Target structure description.
@@ -29,12 +17,6 @@
 	int pres_size;		/* Size of the identifier (enum) */
 
 	/*
-	 * Members of the CHOICE structure.
-	 */
-	asn1_CHOICE_element_t *elements;
-	int elements_count;
-
-	/*
 	 * Tags to members mapping table.
 	 */
 	asn1_TYPE_tag2member_t *tag2el;
diff --git a/skeletons/constr_SEQUENCE.c b/skeletons/constr_SEQUENCE.c
index 6e1747c..06ef4e8 100644
--- a/skeletons/constr_SEQUENCE.c
+++ b/skeletons/constr_SEQUENCE.c
@@ -103,13 +103,13 @@
  * The decoder of the SEQUENCE type.
  */
 ber_dec_rval_t
-SEQUENCE_decode_ber(asn1_TYPE_descriptor_t *sd,
+SEQUENCE_decode_ber(asn1_TYPE_descriptor_t *td,
 	void **struct_ptr, void *ptr, size_t size, int tag_mode) {
 	/*
 	 * Bring closer parts of structure description.
 	 */
-	asn1_SEQUENCE_specifics_t *specs = (asn1_SEQUENCE_specifics_t *)sd->specifics;
-	asn1_SEQUENCE_element_t *elements = specs->elements;
+	asn1_SEQUENCE_specifics_t *specs = (asn1_SEQUENCE_specifics_t *)td->specifics;
+	asn1_TYPE_member_t *elements = td->elements;
 
 	/*
 	 * Parts of the structure being constructed.
@@ -124,7 +124,7 @@
 	ssize_t consumed_myself = 0;	/* Consumed bytes from ptr */
 	int edx;			/* SEQUENCE element's index */
 
-	ASN_DEBUG("Decoding %s as SEQUENCE", sd->name);
+	ASN_DEBUG("Decoding %s as SEQUENCE", td->name);
 	
 	/*
 	 * Create the target structure if it is not present already.
@@ -152,11 +152,11 @@
 		 * perfectly fits our expectations.
 		 */
 
-		rval = ber_check_tags(sd, ctx, ptr, size,
+		rval = ber_check_tags(td, ctx, ptr, size,
 			tag_mode, &ctx->left, 0);
 		if(rval.code != RC_OK) {
 			ASN_DEBUG("%s tagging check failed: %d",
-				sd->name, rval.code);
+				td->name, rval.code);
 			consumed_myself += rval.consumed;
 			RETURN(rval.code);
 		}
@@ -182,7 +182,7 @@
 		 * that member:
 		 * 	step = (<member_number> * 2 + <microphase>).
 		 */
-	  for(edx = (ctx->step >> 1); edx < specs->elements_count;
+	  for(edx = (ctx->step >> 1); edx < td->elements_count;
 			edx++, ctx->step = (ctx->step & ~1) + 2) {
 		void *memb_ptr;		/* Pointer to the member */
 		void **memb_ptr2;	/* Pointer to that pointer */
@@ -198,20 +198,20 @@
 		 * MICROPHASE 1: Synchronize decoding.
 		 */
 		ASN_DEBUG("In %s SEQUENCE left %d, edx=%d opt=%d ec=%d",
-			sd->name, (int)ctx->left,
-			edx, elements[edx].optional, specs->elements_count);
+			td->name, (int)ctx->left,
+			edx, elements[edx].optional, td->elements_count);
 
 		if(ctx->left == 0	/* No more stuff is expected */
 		&& (
 			/* Explicit OPTIONAL specification reaches the end */
-			(edx + elements[edx].optional == specs->elements_count)
+			(edx + elements[edx].optional == td->elements_count)
 			||
 			/* All extensions are optional */
 			(IN_EXTENSION_GROUP(specs, edx)
-				&& specs->ext_before > specs->elements_count)
+				&& specs->ext_before > td->elements_count)
 		   )
 		) {
-			ASN_DEBUG("End of SEQUENCE %s", sd->name);
+			ASN_DEBUG("End of SEQUENCE %s", td->name);
 			/*
 			 * Found the legitimate end of the structure.
 			 */
@@ -224,7 +224,7 @@
 		 */
 		tag_len = ber_fetch_tag(ptr, LEFT, &tlv_tag);
 		ASN_DEBUG("In %s SEQUENCE for %d %s next tag length %d",
-			sd->name, edx, elements[edx].name, (int)tag_len);
+			td->name, edx, elements[edx].name, (int)tag_len);
 		switch(tag_len) {
 		case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE);
 			/* Fall through */
@@ -236,8 +236,8 @@
 		 */
 		use_bsearch = 0;
 		opt_edx_end = edx + elements[edx].optional + 1;
-		if(opt_edx_end > specs->elements_count)
-			opt_edx_end = specs->elements_count;	/* Cap */
+		if(opt_edx_end > td->elements_count)
+			opt_edx_end = td->elements_count;	/* Cap */
 		else if(opt_edx_end - edx > 8) {
 			/* Limit the scope of linear search... */
 			opt_edx_end = edx + 8;
@@ -340,7 +340,7 @@
 					BER_TLV_CONSTRUCTED(ptr),
 					(char *)ptr + tag_len, LEFT - tag_len);
 				ASN_DEBUG("Skip length %d in %s",
-					(int)skip, sd->name);
+					(int)skip, td->name);
 				switch(skip) {
 				case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE);
 					/* Fall through */
@@ -359,7 +359,7 @@
 		 */
 		ctx->step |= 1;		/* Confirm entering next microphase */
 	microphase2:
-		ASN_DEBUG("Inside SEQUENCE %s MF2", sd->name);
+		ASN_DEBUG("Inside SEQUENCE %s MF2", td->name);
 		
 		/*
 		 * Compute the position of the member inside a structure,
@@ -385,7 +385,7 @@
 				memb_ptr2, ptr, LEFT,
 				elements[edx].tag_mode);
 		ASN_DEBUG("In %s SEQUENCE decoded %d %s in %d bytes code %d",
-			sd->name, edx, elements[edx].type->name,
+			td->name, edx, elements[edx].type->name,
 			(int)rval.consumed, rval.code);
 		switch(rval.code) {
 		case RC_OK:
@@ -409,7 +409,7 @@
 	case 4:	/* only 00's expected */
 
 		ASN_DEBUG("SEQUENCE %s Leftover: %ld, size = %ld",
-			sd->name, (long)ctx->left, (long)size);
+			td->name, (long)ctx->left, (long)size);
 
 		/*
 		 * Skip everything until the end of the SEQUENCE.
@@ -445,12 +445,12 @@
 				}
 			}
 
-			if(!IN_EXTENSION_GROUP(specs, specs->elements_count)
+			if(!IN_EXTENSION_GROUP(specs, td->elements_count)
 			|| ctx->phase == 4) {
 				ASN_DEBUG("Unexpected continuation "
 					"of a non-extensible type "
 					"%s (SEQUENCE): %s",
-					sd->name,
+					td->name,
 					ber_tlv_tag_string(tlv_tag));
 				RETURN(RC_FAIL);
 			}
@@ -478,23 +478,22 @@
  * The DER encoder of the SEQUENCE type.
  */
 der_enc_rval_t
-SEQUENCE_encode_der(asn1_TYPE_descriptor_t *sd,
+SEQUENCE_encode_der(asn1_TYPE_descriptor_t *td,
 	void *ptr, int tag_mode, ber_tlv_tag_t tag,
 	asn_app_consume_bytes_f *cb, void *app_key) {
-	asn1_SEQUENCE_specifics_t *specs = (asn1_SEQUENCE_specifics_t *)sd->specifics;
 	size_t computed_size = 0;
 	der_enc_rval_t erval;
 	ssize_t ret;
 	int edx;
 
 	ASN_DEBUG("%s %s as SEQUENCE",
-		cb?"Encoding":"Estimating", sd->name);
+		cb?"Encoding":"Estimating", td->name);
 
 	/*
 	 * Gather the length of the underlying members sequence.
 	 */
-	for(edx = 0; edx < specs->elements_count; edx++) {
-		asn1_SEQUENCE_element_t *elm = &specs->elements[edx];
+	for(edx = 0; edx < td->elements_count; edx++) {
+		asn1_TYPE_member_t *elm = &td->elements[edx];
 		void *memb_ptr;
 		if(elm->optional) {
 			memb_ptr = *(void **)((char *)ptr + elm->memb_offset);
@@ -515,11 +514,11 @@
 	/*
 	 * Encode the TLV for the sequence itself.
 	 */
-	ret = der_write_tags(sd, computed_size, tag_mode, tag, cb, app_key);
+	ret = der_write_tags(td, computed_size, tag_mode, tag, cb, app_key);
 	ASN_DEBUG("Wrote tags: %ld (+%ld)", (long)ret, (long)computed_size);
 	if(ret == -1) {
 		erval.encoded = -1;
-		erval.failed_type = sd;
+		erval.failed_type = td;
 		erval.structure_ptr = ptr;
 		return erval;
 	}
@@ -530,8 +529,8 @@
 	/*
 	 * Encode all members.
 	 */
-	for(edx = 0; edx < specs->elements_count; edx++) {
-		asn1_SEQUENCE_element_t *elm = &specs->elements[edx];
+	for(edx = 0; edx < td->elements_count; edx++) {
+		asn1_TYPE_member_t *elm = &td->elements[edx];
 		der_enc_rval_t tmperval;
 		void *memb_ptr;
 
@@ -548,7 +547,7 @@
 			return tmperval;
 		computed_size -= tmperval.encoded;
 		ASN_DEBUG("Member %d %s of SEQUENCE %s encoded in %d bytes",
-			edx, elm->name, sd->name, tmperval.encoded);
+			edx, elm->name, td->name, tmperval.encoded);
 	}
 
 	if(computed_size != 0) {
@@ -556,7 +555,7 @@
 		 * Encoded size is not equal to the computed size.
 		 */
 		erval.encoded = -1;
-		erval.failed_type = sd;
+		erval.failed_type = td;
 		erval.structure_ptr = ptr;
 	}
 
@@ -566,7 +565,6 @@
 int
 SEQUENCE_print(asn1_TYPE_descriptor_t *td, const void *sptr, int ilevel,
 		asn_app_consume_bytes_f *cb, void *app_key) {
-	asn1_SEQUENCE_specifics_t *specs = (asn1_SEQUENCE_specifics_t *)td->specifics;
 	int edx;
 	int ret;
 
@@ -577,8 +575,8 @@
 	|| cb(" ::= {\n", 7, app_key))
 		return -1;
 
-	for(edx = 0; edx < specs->elements_count; edx++) {
-		asn1_SEQUENCE_element_t *elm = &specs->elements[edx];
+	for(edx = 0; edx < td->elements_count; edx++) {
+		asn1_TYPE_member_t *elm = &td->elements[edx];
 		const void *memb_ptr;
 
 		if(elm->optional) {
@@ -614,7 +612,6 @@
 
 void
 SEQUENCE_free(asn1_TYPE_descriptor_t *td, void *sptr, int contents_only) {
-	asn1_SEQUENCE_specifics_t *specs = (asn1_SEQUENCE_specifics_t *)td->specifics;
 	int edx;
 
 	if(!td || !sptr)
@@ -622,8 +619,8 @@
 
 	ASN_DEBUG("Freeing %s as SEQUENCE", td->name);
 
-	for(edx = 0; edx < specs->elements_count; edx++) {
-		asn1_SEQUENCE_element_t *elm = &specs->elements[edx];
+	for(edx = 0; edx < td->elements_count; edx++) {
+		asn1_TYPE_member_t *elm = &td->elements[edx];
 		void *memb_ptr;
 		if(elm->optional) {
 			memb_ptr = *(void **)((char *)sptr + elm->memb_offset);
@@ -643,7 +640,6 @@
 int
 SEQUENCE_constraint(asn1_TYPE_descriptor_t *td, const void *sptr,
 		asn_app_consume_bytes_f *app_errlog, void *app_key) {
-	asn1_SEQUENCE_specifics_t *specs = (asn1_SEQUENCE_specifics_t *)td->specifics;
 	int edx;
 
 	if(!sptr) {
@@ -655,8 +651,8 @@
 	/*
 	 * Iterate over structure members and check their validity.
 	 */
-	for(edx = 0; edx < specs->elements_count; edx++) {
-		asn1_SEQUENCE_element_t *elm = &specs->elements[edx];
+	for(edx = 0; edx < td->elements_count; edx++) {
+		asn1_TYPE_member_t *elm = &td->elements[edx];
 		const void *memb_ptr;
 
 		if(elm->optional) {
@@ -666,8 +662,20 @@
 			memb_ptr = (const void *)((const char *)sptr + elm->memb_offset);
 		}
 
-		return elm->type->check_constraints(elm->type, memb_ptr,
-			app_errlog, app_key);
+		if(elm->memb_constraints) {
+			int ret = elm->memb_constraints(elm->type, memb_ptr,
+				app_errlog, app_key);
+			if(ret) return ret;
+		} else {
+			int ret = elm->type->check_constraints(elm->type,
+				memb_ptr, app_errlog, app_key);
+			if(ret) return ret;
+			/*
+			 * Cannot inherit it earlier:
+			 * need to make sure we get the updated version.
+			 */
+			elm->memb_constraints = elm->type->check_constraints;
+		}
 	}
 
 	return 0;
diff --git a/skeletons/constr_SEQUENCE.h b/skeletons/constr_SEQUENCE.h
index 17754bb..1e282c2 100644
--- a/skeletons/constr_SEQUENCE.h
+++ b/skeletons/constr_SEQUENCE.h
@@ -7,18 +7,6 @@
 
 #include <constr_TYPE.h>
 
-/*
- * A single element of the SEQUENCE type.
- */
-typedef struct asn1_SEQUENCE_element_s {
-	int memb_offset;		/* Offset of the element */
-	int optional;			/* Whether the element is optional */
-	ber_tlv_tag_t tag;		/* Outmost (most immediate) tag */
-	int tag_mode;		/* IMPLICIT/no/EXPLICIT tag at current level */
-	asn1_TYPE_descriptor_t *type;	/* Member type descriptor */
-	char *name;			/* ASN.1 identifier of the element */
-} asn1_SEQUENCE_element_t;
-
 typedef struct asn1_SEQUENCE_specifics_s {
 	/*
 	 * Target structure description.
@@ -27,12 +15,6 @@
 	int ctx_offset;		/* Offset of the ber_dec_ctx_t member */
 
 	/*
-	 * Members of the SEQUENCE structure.
-	 */
-	asn1_SEQUENCE_element_t *elements;
-	int elements_count;
-
-	/*
 	 * Tags to members mapping table (sorted).
 	 */
 	asn1_TYPE_tag2member_t *tag2el;
diff --git a/skeletons/constr_SEQUENCE_OF.c b/skeletons/constr_SEQUENCE_OF.c
index 0370a2d..0a58f09 100644
--- a/skeletons/constr_SEQUENCE_OF.c
+++ b/skeletons/constr_SEQUENCE_OF.c
@@ -9,18 +9,17 @@
  * The DER encoder of the SEQUENCE OF type.
  */
 der_enc_rval_t
-SEQUENCE_OF_encode_der(asn1_TYPE_descriptor_t *sd, void *ptr,
+SEQUENCE_OF_encode_der(asn1_TYPE_descriptor_t *td, void *ptr,
 	int tag_mode, ber_tlv_tag_t tag,
 	asn_app_consume_bytes_f *cb, void *app_key) {
-	asn1_SET_OF_specifics_t *specs = (asn1_SET_OF_specifics_t *)sd->specifics;
-	asn1_SET_OF_element_t *elm = specs->element;
+	asn1_TYPE_member_t *elm = td->elements;
 	A_SEQUENCE_OF(void) *list;
 	size_t computed_size = 0;
 	ssize_t encoding_size = 0;
 	der_enc_rval_t erval;
 	int edx;
 
-	ASN_DEBUG("Estimating size of SEQUENCE OF %s", sd->name);
+	ASN_DEBUG("Estimating size of SEQUENCE OF %s", td->name);
 
 	/*
 	 * Gather the length of the underlying members sequence.
@@ -39,11 +38,11 @@
 	/*
 	 * Encode the TLV for the sequence itself.
 	 */
-	encoding_size = der_write_tags(sd, computed_size, tag_mode, tag,
+	encoding_size = der_write_tags(td, computed_size, tag_mode, tag,
 		cb, app_key);
 	if(encoding_size == -1) {
 		erval.encoded = -1;
-		erval.failed_type = sd;
+		erval.failed_type = td;
 		erval.structure_ptr = ptr;
 		return erval;
 	}
@@ -54,7 +53,7 @@
 		return erval;
 	}
 
-	ASN_DEBUG("Encoding members of SEQUENCE OF %s", sd->name);
+	ASN_DEBUG("Encoding members of SEQUENCE OF %s", td->name);
 
 	/*
 	 * Encode all members.
@@ -74,7 +73,7 @@
 		 * Encoded size is not equal to the computed size.
 		 */
 		erval.encoded = -1;
-		erval.failed_type = sd;
+		erval.failed_type = td;
 		erval.structure_ptr = ptr;
 	} else {
 		erval.encoded = computed_size;
diff --git a/skeletons/constr_SET.c b/skeletons/constr_SET.c
index d1036c9..d1a81be 100644
--- a/skeletons/constr_SET.c
+++ b/skeletons/constr_SET.c
@@ -93,13 +93,13 @@
  * The decoder of the SET type.
  */
 ber_dec_rval_t
-SET_decode_ber(asn1_TYPE_descriptor_t *sd,
+SET_decode_ber(asn1_TYPE_descriptor_t *td,
 	void **struct_ptr, void *ptr, size_t size, int tag_mode) {
 	/*
 	 * Bring closer parts of structure description.
 	 */
-	asn1_SET_specifics_t *specs = (asn1_SET_specifics_t *)sd->specifics;
-	asn1_SET_element_t *elements = specs->elements;
+	asn1_SET_specifics_t *specs = (asn1_SET_specifics_t *)td->specifics;
+	asn1_TYPE_member_t *elements = td->elements;
 
 	/*
 	 * Parts of the structure being constructed.
@@ -114,7 +114,7 @@
 	ssize_t consumed_myself = 0;	/* Consumed bytes from ptr */
 	int edx;			/* SET element's index */
 
-	ASN_DEBUG("Decoding %s as SET", sd->name);
+	ASN_DEBUG("Decoding %s as SET", td->name);
 	
 	/*
 	 * Create the target structure if it is not present already.
@@ -142,11 +142,11 @@
 		 * perfectly fits our expectations.
 		 */
 
-		rval = ber_check_tags(sd, ctx, ptr, size,
+		rval = ber_check_tags(td, ctx, ptr, size,
 			tag_mode, &ctx->left, 0);
 		if(rval.code != RC_OK) {
 			ASN_DEBUG("%s tagging check failed: %d",
-				sd->name, rval.code);
+				td->name, rval.code);
 			consumed_myself += rval.consumed;
 			RETURN(rval.code);
 		}
@@ -176,7 +176,7 @@
 		 * canonical order of their tags. So, there is a room
 		 * for optimization.
 		 */
-	  for(edx = (ctx->step >> 1); edx < specs->elements_count;
+	  for(edx = (ctx->step >> 1); edx < td->elements_count;
 			ctx->step = (ctx->step & ~1) + 2,
 				edx = (ctx->step >> 1)) {
 		void *memb_ptr;		/* Pointer to the member */
@@ -247,7 +247,7 @@
 			} else if(specs->extensible == 0) {
 				ASN_DEBUG("Unexpected tag %s "
 					"in non-extensible SET %s",
-					ber_tlv_tag_string(tlv_tag), sd->name);
+					ber_tlv_tag_string(tlv_tag), td->name);
 				RETURN(RC_FAIL);
 			} else {
 				/* Skip this tag */
@@ -285,7 +285,7 @@
 		 */
 		if(ASN_SET_ISPRESENT2((char *)st + specs->pres_offset, edx)) {
 			ASN_DEBUG("SET %s: Duplicate element %s (%d)",
-				sd->name, elements[edx].name, edx);
+				td->name, elements[edx].name, edx);
 			RETURN(RC_FAIL);
 		}
 		
@@ -335,7 +335,7 @@
 	case 3:
 	case 4:	/* Only 00 is expected */
 		ASN_DEBUG("SET %s Leftover: %ld, size = %ld",
-			sd->name, (long)ctx->left, (long)size);
+			td->name, (long)ctx->left, (long)size);
 
 		/*
 		 * Skip everything until the end of the SET.
@@ -374,7 +374,7 @@
 			if(specs->extensible == 0 || ctx->phase == 4) {
 				ASN_DEBUG("Unexpected continuation "
 					"of a non-extensible type %s",
-					sd->name);
+					td->name);
 				RETURN(RC_FAIL);
 			}
 
@@ -395,7 +395,7 @@
 		/*
 		 * Check that all mandatory elements are present.
 		 */
-		for(edx = 0; edx < specs->elements_count;
+		for(edx = 0; edx < td->elements_count;
 			edx += (8 * sizeof(specs->_mandatory_elements[0]))) {
 			unsigned int midx, pres, must;
 
@@ -411,7 +411,7 @@
 				ASN_DEBUG("One or more mandatory elements "
 					"of a SET %s %d (%08x.%08x)=%08x "
 					"are not present",
-					sd->name,
+					td->name,
 					midx,
 					pres,
 					must,
@@ -431,13 +431,13 @@
  * The DER encoder of the SET type.
  */
 der_enc_rval_t
-SET_encode_der(asn1_TYPE_descriptor_t *sd,
+SET_encode_der(asn1_TYPE_descriptor_t *td,
 	void *ptr, int tag_mode, ber_tlv_tag_t tag,
 	asn_app_consume_bytes_f *cb, void *app_key) {
-	asn1_SET_specifics_t *specs = (asn1_SET_specifics_t *)sd->specifics;
+	asn1_SET_specifics_t *specs = (asn1_SET_specifics_t *)td->specifics;
 	size_t computed_size = 0;
 	der_enc_rval_t my_erval;
-	int t2m_build_own = (specs->tag2el_count != specs->elements_count);
+	int t2m_build_own = (specs->tag2el_count != td->elements_count);
 	asn1_TYPE_tag2member_t *t2m;
 	int t2m_count;
 	ssize_t ret;
@@ -447,10 +447,10 @@
 	 * Use existing, or build our own tags map.
 	 */
 	if(t2m_build_own) {
-		(void *)t2m = alloca(specs->elements_count * sizeof(t2m[0]));
+		(void *)t2m = alloca(td->elements_count * sizeof(t2m[0]));
 		if(!t2m) {	/* There are such platforms */
 			my_erval.encoded = -1;
-			my_erval.failed_type = sd;
+			my_erval.failed_type = td;
 			my_erval.structure_ptr = ptr;
 			return my_erval;
 		}
@@ -467,8 +467,8 @@
 	/*
 	 * Gather the length of the underlying members sequence.
 	 */
-	for(edx = 0; edx < specs->elements_count; edx++) {
-		asn1_SET_element_t *elm = &specs->elements[edx];
+	for(edx = 0; edx < td->elements_count; edx++) {
+		asn1_TYPE_member_t *elm = &td->elements[edx];
 		der_enc_rval_t erval;
 		void *memb_ptr;
 
@@ -513,7 +513,7 @@
 	/*
 	 * Finalize order of the components.
 	 */
-	assert(t2m_count == specs->elements_count);
+	assert(t2m_count == td->elements_count);
 	if(t2m_build_own) {
 		/*
 		 * Sort the underlying members according to their
@@ -529,10 +529,10 @@
 	/*
 	 * Encode the TLV for the sequence itself.
 	 */
-	ret = der_write_tags(sd, computed_size, tag_mode, tag, cb, app_key);
+	ret = der_write_tags(td, computed_size, tag_mode, tag, cb, app_key);
 	if(ret == -1) {
 		my_erval.encoded = -1;
-		my_erval.failed_type = sd;
+		my_erval.failed_type = td;
 		my_erval.structure_ptr = ptr;
 		return my_erval;
 	}
@@ -543,13 +543,13 @@
 	/*
 	 * Encode all members.
 	 */
-	for(edx = 0; edx < specs->elements_count; edx++) {
-		asn1_SET_element_t *elm;
+	for(edx = 0; edx < td->elements_count; edx++) {
+		asn1_TYPE_member_t *elm;
 		der_enc_rval_t erval;
 		void *memb_ptr;
 
 		/* Encode according to the tag order */
-		elm = &specs->elements[t2m[edx].el_no];
+		elm = &td->elements[t2m[edx].el_no];
 
 		if(elm->optional) {
 			memb_ptr = *(void **)((char *)ptr + elm->memb_offset);
@@ -570,7 +570,7 @@
 		 * Encoded size is not equal to the computed size.
 		 */
 		my_erval.encoded = -1;
-		my_erval.failed_type = sd;
+		my_erval.failed_type = td;
 		my_erval.structure_ptr = ptr;
 	}
 
@@ -580,7 +580,6 @@
 int
 SET_print(asn1_TYPE_descriptor_t *td, const void *sptr, int ilevel,
 		asn_app_consume_bytes_f *cb, void *app_key) {
-	asn1_SET_specifics_t *specs = (asn1_SET_specifics_t *)td->specifics;
 	int edx;
 	int ret;
 
@@ -591,8 +590,8 @@
 	|| cb(" ::= {\n", 7, app_key))
 		return -1;
 
-	for(edx = 0; edx < specs->elements_count; edx++) {
-		asn1_SET_element_t *elm = &specs->elements[edx];
+	for(edx = 0; edx < td->elements_count; edx++) {
+		asn1_TYPE_member_t *elm = &td->elements[edx];
 		const void *memb_ptr;
 
 		if(elm->optional) {
@@ -627,7 +626,6 @@
 
 void
 SET_free(asn1_TYPE_descriptor_t *td, void *ptr, int contents_only) {
-	asn1_SET_specifics_t *specs = (asn1_SET_specifics_t *)td->specifics;
 	int edx;
 
 	if(!td || !ptr)
@@ -635,8 +633,8 @@
 
 	ASN_DEBUG("Freeing %s as SET", td->name);
 
-	for(edx = 0; edx < specs->elements_count; edx++) {
-		asn1_SET_element_t *elm = &specs->elements[edx];
+	for(edx = 0; edx < td->elements_count; edx++) {
+		asn1_TYPE_member_t *elm = &td->elements[edx];
 		void *memb_ptr;
 		if(elm->optional) {
 			memb_ptr = *(void **)((char *)ptr + elm->memb_offset);
@@ -668,8 +666,8 @@
 	/*
 	 * Iterate over structure members and check their validity.
 	 */
-	for(edx = 0; edx < specs->elements_count; edx++) {
-		asn1_SET_element_t *elm = &specs->elements[edx];
+	for(edx = 0; edx < td->elements_count; edx++) {
+		asn1_TYPE_member_t *elm = &td->elements[edx];
 		const void *memb_ptr;
 
 		if(elm->optional) {
@@ -689,8 +687,20 @@
 			memb_ptr = (const void *)((const char *)sptr + elm->memb_offset);
 		}
 
-		return elm->type->check_constraints(elm->type, memb_ptr,
-			app_errlog, app_key);
+		if(elm->memb_constraints) {
+			int ret = elm->memb_constraints(elm->type, memb_ptr,
+				app_errlog, app_key);
+			if(ret) return ret;
+		} else {
+			int ret = elm->type->check_constraints(elm->type,
+				memb_ptr, app_errlog, app_key);
+			if(ret) return ret;
+			/*
+			 * Cannot inherit it earlier:
+			 * need to make sure we get the updated version.
+			 */
+			elm->memb_constraints = elm->type->check_constraints;
+		}
 	}
 
 	return 0;
diff --git a/skeletons/constr_SET.h b/skeletons/constr_SET.h
index 8cb3fa8..eab2c30 100644
--- a/skeletons/constr_SET.h
+++ b/skeletons/constr_SET.h
@@ -7,18 +7,6 @@
 
 #include <constr_TYPE.h>
 
-/*
- * Description of a single element of the SET type.
- */
-typedef struct asn1_SET_element_s {
-	int memb_offset;		/* Offset of the element */
-	int optional;			/* Whether the element is optional */
-	ber_tlv_tag_t tag;		/* Outmost (most immediate) tag */
-	int tag_mode;		/* IMPLICIT/no/EXPLICIT tag at current level */
-	asn1_TYPE_descriptor_t *type;	/* Member type descriptor */
-	char *name;			/* ASN.1 identifier of the element */
-} asn1_SET_element_t;
-
 
 typedef struct asn1_SET_specifics_s {
 	/*
@@ -29,12 +17,6 @@
 	int pres_offset;	/* Offset of _presence_map member */
 
 	/*
-	 * Members of the SET structure.
-	 */
-	asn1_SET_element_t *elements;
-	int elements_count;
-
-	/*
 	 * Tags to members mapping table (sorted).
 	 */
 	asn1_TYPE_tag2member_t *tag2el;
diff --git a/skeletons/constr_SET_OF.c b/skeletons/constr_SET_OF.c
index 511207d..ecf16f0 100644
--- a/skeletons/constr_SET_OF.c
+++ b/skeletons/constr_SET_OF.c
@@ -60,13 +60,13 @@
  * The decoder of the SET OF type.
  */
 ber_dec_rval_t
-SET_OF_decode_ber(asn1_TYPE_descriptor_t *sd,
+SET_OF_decode_ber(asn1_TYPE_descriptor_t *td,
 	void **struct_ptr, void *ptr, size_t size, int tag_mode) {
 	/*
 	 * Bring closer parts of structure description.
 	 */
-	asn1_SET_OF_specifics_t *specs = (asn1_SET_OF_specifics_t *)sd->specifics;
-	asn1_SET_OF_element_t *element = specs->element;
+	asn1_SET_OF_specifics_t *specs = (asn1_SET_OF_specifics_t *)td->specifics;
+	asn1_TYPE_member_t *element = td->elements;	/* Single one */
 
 	/*
 	 * Parts of the structure being constructed.
@@ -80,7 +80,7 @@
 
 	ssize_t consumed_myself = 0;	/* Consumed bytes from ptr */
 
-	ASN_DEBUG("Decoding %s as SET OF", sd->name);
+	ASN_DEBUG("Decoding %s as SET OF", td->name);
 	
 	/*
 	 * Create the target structure if it is not present already.
@@ -108,11 +108,11 @@
 		 * perfectly fits our expectations.
 		 */
 
-		rval = ber_check_tags(sd, ctx, ptr, size,
+		rval = ber_check_tags(td, ctx, ptr, size,
 			tag_mode, &ctx->left, 0);
 		if(rval.code != RC_OK) {
 			ASN_DEBUG("%s tagging check failed: %d",
-				sd->name, rval.code);
+				td->name, rval.code);
 			consumed_myself += rval.consumed;
 			RETURN(rval.code);
 		}
@@ -143,7 +143,7 @@
 		 */
 
 		if(ctx->left == 0) {
-			ASN_DEBUG("End of SET OF %s", sd->name);
+			ASN_DEBUG("End of SET OF %s", td->name);
 			/*
 			 * No more things to decode.
 			 * Exit out of here.
@@ -185,9 +185,9 @@
 			 */
 		    } else {
 			ASN_DEBUG("Unexpected tag %s fixed SET OF %s",
-				ber_tlv_tag_string(tlv_tag), sd->name);
+				ber_tlv_tag_string(tlv_tag), td->name);
 			ASN_DEBUG("%s SET OF has tag %s",
-				sd->name, ber_tlv_tag_string(element->tag));
+				td->name, ber_tlv_tag_string(element->tag));
 			RETURN(RC_FAIL);
 		    }
 		}
@@ -204,7 +204,7 @@
 		rval = element->type->ber_decoder(element->type,
 				&ctx->ptr, ptr, LEFT, 0);
 		ASN_DEBUG("In %s SET OF %s code %d consumed %d",
-			sd->name, element->type->name,
+			td->name, element->type->name,
 			rval.code, (int)rval.consumed);
 		switch(rval.code) {
 		case RC_OK:
@@ -305,11 +305,10 @@
  * The DER encoder of the SET OF type.
  */
 der_enc_rval_t
-SET_OF_encode_der(asn1_TYPE_descriptor_t *sd, void *ptr,
+SET_OF_encode_der(asn1_TYPE_descriptor_t *td, void *ptr,
 	int tag_mode, ber_tlv_tag_t tag,
 	asn_app_consume_bytes_f *cb, void *app_key) {
-	asn1_SET_OF_specifics_t *specs = (asn1_SET_OF_specifics_t *)sd->specifics;
-	asn1_SET_OF_element_t *elm = specs->element;
+	asn1_TYPE_member_t *elm = td->elements;
 	asn1_TYPE_descriptor_t *elm_type = elm->type;
 	der_type_encoder_f *der_encoder = elm_type->der_encoder;
 	A_SET_OF(void) *list;
@@ -321,7 +320,7 @@
 	int ret;
 	int edx;
 
-	ASN_DEBUG("Estimating size for SET OF %s", sd->name);
+	ASN_DEBUG("Estimating size for SET OF %s", td->name);
 
 	/*
 	 * Gather the length of the underlying members sequence.
@@ -342,11 +341,11 @@
 	/*
 	 * Encode the TLV for the sequence itself.
 	 */
-	encoding_size = der_write_tags(sd, computed_size, tag_mode, tag,
+	encoding_size = der_write_tags(td, computed_size, tag_mode, tag,
 		cb, app_key);
 	if(encoding_size == -1) {
 		erval.encoded = -1;
-		erval.failed_type = sd;
+		erval.failed_type = td;
 		erval.structure_ptr = ptr;
 		return erval;
 	}
@@ -365,12 +364,12 @@
 	(void *)encoded_els = MALLOC(list->count * sizeof(encoded_els[0]));
 	if(encoded_els == NULL) {
 		erval.encoded = -1;
-		erval.failed_type = sd;
+		erval.failed_type = td;
 		erval.structure_ptr = ptr;
 		return erval;
 	}
 
-	ASN_DEBUG("Encoding members of %s SET OF", sd->name);
+	ASN_DEBUG("Encoding members of %s SET OF", td->name);
 
 	/*
 	 * Encode all members.
@@ -391,7 +390,7 @@
 				FREEMEM(encoded_els[edx].buf);
 			FREEMEM(encoded_els);
 			erval.encoded = -1;
-			erval.failed_type = sd;
+			erval.failed_type = td;
 			erval.structure_ptr = ptr;
 			return erval;
 		}
@@ -436,7 +435,7 @@
 		 * encoded size is not equal to the computed size.
 		 */
 		erval.encoded = -1;
-		erval.failed_type = sd;
+		erval.failed_type = td;
 		erval.structure_ptr = ptr;
 	} else {
 		erval.encoded = computed_size;
@@ -448,8 +447,7 @@
 int
 SET_OF_print(asn1_TYPE_descriptor_t *td, const void *sptr, int ilevel,
 		asn_app_consume_bytes_f *cb, void *app_key) {
-	asn1_SET_OF_specifics_t *specs = (asn1_SET_OF_specifics_t *)td->specifics;
-	asn1_SET_OF_element_t *element = specs->element;
+	asn1_TYPE_member_t *element = td->elements;
 	const A_SET_OF(void) *list;
 	int ret;
 	int i;
@@ -486,8 +484,7 @@
 void
 SET_OF_free(asn1_TYPE_descriptor_t *td, void *ptr, int contents_only) {
 	if(td && ptr) {
-		asn1_SET_OF_specifics_t *specs = (asn1_SET_OF_specifics_t *)td->specifics;
-		asn1_SET_OF_element_t *element = specs->element;
+		asn1_TYPE_member_t *element = td->elements;
 		A_SET_OF(void) *list;
 		int i;
 
@@ -514,8 +511,8 @@
 int
 SET_OF_constraint(asn1_TYPE_descriptor_t *td, const void *sptr,
 		asn_app_consume_bytes_f *app_errlog, void *app_key) {
-	asn1_SET_OF_specifics_t *specs = (asn1_SET_OF_specifics_t *)td->specifics;
-	asn1_SET_OF_element_t *element = specs->element;
+	asn1_TYPE_member_t *element = td->elements;
+	asn_constr_check_f *constr;
 	const A_SET_OF(void) *list;
 	int i;
 
@@ -526,12 +523,30 @@
 	}
 
 	(const void *)list = sptr;
+
+	constr = element->memb_constraints;
+	if(!constr) constr = element->type->check_constraints;
+
+	/*
+	 * Iterate over the members of an array.
+	 * Validate each in turn, until one fails.
+	 */
 	for(i = 0; i < list->count; i++) {
 		const void *memb_ptr = list->array[i];
+		int ret;
+
 		if(!memb_ptr) continue;
-		return element->type->check_constraints(element->type, memb_ptr,
-			app_errlog, app_key);
+
+		ret = constr(element->type, memb_ptr, app_errlog, app_key);
+		if(ret) return ret;
 	}
 
+	/*
+	 * Cannot inherit it eralier:
+	 * need to make sure we get the updated version.
+	 */
+	if(!element->memb_constraints)
+		element->memb_constraints = element->type->check_constraints;
+
 	return 0;
 }
diff --git a/skeletons/constr_SET_OF.h b/skeletons/constr_SET_OF.h
index e2c6d8f..0dd6040 100644
--- a/skeletons/constr_SET_OF.h
+++ b/skeletons/constr_SET_OF.h
@@ -7,22 +7,12 @@
 
 #include <constr_TYPE.h>
 
-typedef struct asn1_SET_OF_element_s {
-	ber_tlv_tag_t tag;		/* Outmost (most immediate) tag */
-	asn1_TYPE_descriptor_t *type;	/* Member type descriptor */
-} asn1_SET_OF_element_t;
-
 typedef struct asn1_SET_OF_specifics_s {
 	/*
 	 * Target structure description.
 	 */
 	int struct_size;	/* Size of the target structure. */
 	int ctx_offset;		/* Offset of the ber_dec_ctx_t member */
-
-	/*
-	 * Members of the SET OF list.
-	 */
-	asn1_SET_OF_element_t *element;
 } asn1_SET_OF_specifics_t;
 
 /*
diff --git a/skeletons/constr_TYPE.h b/skeletons/constr_TYPE.h
index da3a2db..67f9c55 100644
--- a/skeletons/constr_TYPE.h
+++ b/skeletons/constr_TYPE.h
@@ -13,6 +13,7 @@
 #include <constraints.h>
 
 struct asn1_TYPE_descriptor_s;	/* Forward declaration */
+struct asn1_TYPE_member_s;	/* Forward declaration */
 
 /*
  * Free the structure according to its specification.
@@ -43,7 +44,7 @@
 typedef ber_tlv_tag_t (asn_outmost_tag_f)(
 		struct asn1_TYPE_descriptor_s *type_descriptor,
 		const void *struct_ptr, int tag_mode, ber_tlv_tag_t tag);
-/* The instance of the above function type */
+/* The instance of the above function type; used internally. */
 asn_outmost_tag_f asn1_TYPE_outmost_tag;
 
 
@@ -77,6 +78,12 @@
 	int last_tag_form;	/* Acceptable form of the tag (prim, constr) */
 
 	/*
+	 * An ASN.1 production type members (members of SEQUENCE, SET, CHOICE).
+	 */
+	struct asn1_TYPE_member_s *elements;
+	int elements_count;
+
+	/*
 	 * Additional information describing the type, used by appropriate
 	 * functions above.
 	 */
@@ -84,6 +91,19 @@
 } asn1_TYPE_descriptor_t;
 
 /*
+ * An element of the constructed type, i.e. SEQUENCE, SET, CHOICE.
+ */
+typedef struct asn1_TYPE_member_s {
+	int optional;			/* Whether the element is optional */
+	int memb_offset;		/* Offset of the element */
+	ber_tlv_tag_t tag;		/* Outmost (most immediate) tag */
+	int tag_mode;		/* IMPLICIT/no/EXPLICIT tag at current level */
+	asn1_TYPE_descriptor_t *type;	/* Member type descriptor */
+	asn_constr_check_f *memb_constraints;	/* Constraints validator */
+	char *name;			/* ASN.1 identifier of the element */
+} asn1_TYPE_member_t;
+
+/*
  * BER tag to element number mapping.
  */
 typedef struct asn1_TYPE_tag2member_s {