PER visible constraints are used to select the native representation for INTEGER types


git-svn-id: https://asn1c.svn.sourceforge.net/svnroot/asn1c/trunk@957 59561ff5-6e30-0410-9f3c-9617f08c8826
diff --git a/libasn1compiler/asn1c_misc.c b/libasn1compiler/asn1c_misc.c
index 8c5bb62..bcf062f 100644
--- a/libasn1compiler/asn1c_misc.c
+++ b/libasn1compiler/asn1c_misc.c
@@ -1,7 +1,8 @@
 #include "asn1c_internal.h"
 #include "asn1c_misc.h"
 
-#include <asn1fix_export.h>
+#include <asn1fix_crange.h>	/* constraint groker from libasn1fix */
+#include <asn1fix_export.h>	/* other exportable stuff from libasn1fix */
 
 /*
  * Checks that the given string is not a reserved C/C++ keyword.
@@ -189,7 +190,9 @@
 	case ASN_BASIC_INTEGER:
 	case ASN_BASIC_ENUMERATED:
 	case ASN_BASIC_REAL:
-		if((arg->flags & A1C_USE_NATIVE_TYPES)) {
+		if((expr->expr_type == ASN_BASIC_REAL
+			&& (arg->flags & A1C_USE_NATIVE_TYPES))
+		|| asn1c_type_fits_long(arg, expr)) {
 			switch(_format) {
 			case TNF_CTYPE:
 			case TNF_RSAFE:
@@ -239,3 +242,84 @@
 	return typename;
 }
 
+/*
+ * Check whether the specified INTEGER or ENUMERATED type can be represented
+ * using the generic 'long' type.
+ */
+enum asn1c_fitslong_e
+asn1c_type_fits_long(arg_t *arg, asn1p_expr_t *expr) {
+	asn1cnst_range_t *range = 0;
+	asn1cnst_edge_t left;
+	asn1cnst_edge_t right;
+	asn1p_expr_t *v;
+
+/*
+ * Since we don't know the sizeof(long) on the possible target platform
+ * which will be compiling the code generated by asn1c, let's play it
+ * simple: long's range is equal to or greater than int32_t.
+ */
+#define	LEFTMIN		INT32_MIN
+#define	RIGHTMAX	INT32_MAX
+
+	/* Descend to the terminal type */
+	expr = asn1f_find_terminal_type_ex(arg->asn, expr);
+	if(expr == 0) return FL_NOTFIT;
+
+	/* The "fits into long" operation is relevant only for integer types */
+	switch(expr->expr_type) {
+	case ASN_BASIC_INTEGER:
+	case ASN_BASIC_ENUMERATED:
+		break;
+	default:
+		return FL_NOTFIT;
+	}
+
+	/*
+	 * First, evaluate the range of explicitly given identifiers.
+	 */
+	TQ_FOR(v, &(expr->members), next) {
+		if(v->expr_type != A1TC_UNIVERVAL)
+			continue;
+		if(v->value->value.v_integer < LEFTMIN
+		|| v->value->value.v_integer > RIGHTMAX)
+			return FL_NOTFIT;
+	}
+
+	/*
+	 * Second, pull up the PER visible range of the INTEGER.
+	 */
+	if(expr->combined_constraints)
+		range = asn1constraint_compute_PER_range(expr->expr_type,
+			expr->combined_constraints, ACT_EL_RANGE, 0, 0, 0);
+	if(!range
+	|| range->empty_constraint
+	|| range->extensible
+	|| range->incompatible
+	|| range->not_PER_visible
+	) {
+		asn1constraint_range_free(range);
+		return (arg->flags & A1C_USE_NATIVE_TYPES)
+			? FL_FORCED : FL_NOTFIT;
+	}
+
+	left = range->left;
+	right = range->right;
+	asn1constraint_range_free(range);
+
+	/* If some fixed value is outside of target range, not fit */
+	if(left.type == ARE_VALUE
+			&& (left.value < LEFTMIN || left.value > RIGHTMAX))
+		return FL_NOTFIT;
+	if(right.type == ARE_VALUE
+			&& (right.value > RIGHTMAX || right.value < LEFTMIN))
+		return FL_NOTFIT;
+
+	/* If the range is open, fits only if -fnative-types is given */
+	if(left.type != ARE_VALUE || right.type != ARE_VALUE) {
+		return (arg->flags & A1C_USE_NATIVE_TYPES)
+			? FL_FORCED : FL_NOTFIT;
+	}
+
+	return FL_FITSOK;
+}
+