Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions analyser/conversion_checker_expr.c2
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ fn ExprWidth getExprWidth(const Expr* e) {
return getTypeWidth(e.getType());
case Type:
break;
case Template:
case Call:
return getTypeWidth(e.getType());
case InitList:
Expand Down
74 changes: 50 additions & 24 deletions analyser/module_analyser_call.c2
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,31 @@ const char[] DiagTooManyArgs = "too many arguments to %sfunction call, expected
const char[] DiagTooFewArgs = "too few arguments to %sfunction call, expected %d, have %d";
const char[] NoteDeclaredHere = "'%s' is defined here";

fn QualType Analyser.analyseTemplateExpr(Analyser* ma, Expr** e_ptr) {
Expr* e = *e_ptr;
TemplateExpr* tp = (TemplateExpr*)e;
Expr** func = tp.getFunc2();
Expr* origFn = tp.getFunc(); // store here to avoid the likely inserted FunctionPointerDecay cast
QualType qt = ma.analyseExpr(func, true, RHS);
if (qt.isInvalid()) return QualType_Invalid;
FunctionType* ft = qt.getFunctionTypeOrNil();
if (!ft) {
ma.errorRange(origFn.getLoc(), origFn.getRange(), "object type %s is not a function template", qt.diagName());
return QualType_Invalid;
}
FunctionDecl* fd = ft.getDecl();
if (!fd.isTemplate() || fd.isTemplateTypeFunction()) {
ma.errorRange(e.getLoc(), e.getRange(), "function %s is not a template function", fd.asDecl().getFullName());
return QualType_Invalid;
}

FunctionDecl* fd2 = ma.instantiateFunctionTemplate(fd, tp.getInstanceASTIdx(), tp.getArgs(), tp.getNumArgs());
if (!fd2) return QualType_Invalid;
fd2.asDecl().setUsed();
tp.setDecl(fd2.asDecl());
return fd2.asDecl().getType();
}

fn QualType Analyser.analyseCallExpr(Analyser* ma, Expr** e_ptr) {
Expr* e = *e_ptr;
CallExpr* call = (CallExpr*)e;
Expand Down Expand Up @@ -60,17 +85,10 @@ fn QualType Analyser.analyseCallExpr(Analyser* ma, Expr** e_ptr) {
if (fd.hasAttrNoReturn()) call.setNoreturn();

if (fd.isTemplate()) {
if (!call.getTemplateArg()) {
ma.errorRange(e.getLoc(), e.getRange(), "function %s requires a template argument", fd.asDecl().getFullName());
return QualType_Invalid;
}
fd = ma.instantiateTemplateFunction(call, fd);
if (!fd) return QualType_Invalid;
} else {
if (call.getTemplateArg()) {
ma.errorRange(e.getLoc(), e.getRange(), "function %s is not a template function", fd.asDecl().getFullName());
return QualType_Invalid;
}
// TODO handle default type arguments
// TODO auto-instantiate based on actual argument types
ma.errorRange(e.getLoc(), e.getRange(), "function %s requires a template argument", fd.asDecl().getFullName());
return QualType_Invalid;
}

if (fd.hasAttrDeprecated() && !ma.warnings.no_deprecated) {
Expand Down Expand Up @@ -624,12 +642,18 @@ fn void Analyser.opaque_callback(void* arg, SrcLoc loc, Decl* d) {
ma.error(loc," using opaque type '%s'", qt.diagName());
}

fn FunctionDecl* Analyser.instantiateTemplateFunction(Analyser* ma, CallExpr* call, FunctionDecl* fd) {
TypeRef* template_arg = call.getTemplateArg();
fn FunctionDecl* Analyser.instantiateFunctionTemplate(Analyser* ma, FunctionDecl* fd, u16 instance_ast_idx, Expr** args, u32 num_args) {
// Only handle first argument for now, convert to type
TypeRef* template_arg = ma.getTemplateArg(*args);
if (!template_arg) return nil;
QualType templateType = ma.analyseTypeRef(template_arg);
if (templateType.isInvalid()) return nil;

FunctionDecl* instance = ma.mod.findInstance(fd, templateType);
// TODO create instiator, analyse/evaluate template expressions,
// initialize TemplateSubst array from values or qualtypes,
// compute instance name and check if name exists already

FunctionDecl* instance = (FunctionDecl*)ma.mod.findInstance(fd.asDecl(), templateType);
if (!instance) {
// note: template_arg decl is set here
bool used_opaque = false;
Expand All @@ -639,11 +663,14 @@ fn FunctionDecl* Analyser.instantiateTemplateFunction(Analyser* ma, CallExpr* ca
Decl* d = (Decl*)std;
used_opaque = (std.isOpaque() && d.getModule() != ma.mod);
}
// TODO: use TemplateSpec in Instantiator
const TemplateSpec* spec = fd.getTemplateSpec();
Instantiator inst = {
.c = ma.context,
.ref = template_arg,
.template_name = fd.getTemplateNameIdx(),
.instance_ast_idx = call.getInstanceASTIdx(),
.template_vars = spec.getTemplateVars(),
.template_len = spec.getTemplateLen(),
.instance_ast_idx = instance_ast_idx,
.used_opaque = used_opaque,
.arg = ma,
.on_error = Analyser.opaque_callback,
Expand All @@ -654,6 +681,13 @@ fn FunctionDecl* Analyser.instantiateTemplateFunction(Analyser* ma, CallExpr* ca
if (ma.has_error) return nil;
d.setChecked();

// add instance to avoid recursive instantiation for the same type
u16 instance_idx = ma.mod.addInstance(fd.asDecl(), templateType, instance.asDecl());
char[64] name;
// TODO: use a more readable name, eg: max$i32
create_template_name(name, fd.asDecl().getName(), instance_idx);
d.setNameIdx(ma.astPool.addStr(name, true));

// Note: we need a separate scope for the body
Module* template_mod = fd.asDecl().getModule();
Analyser* analyser = create(ma.diags, ma.context, ma.astPool, ma.builder, ma.allmodules, ma.warnings);
Expand All @@ -669,15 +703,7 @@ fn FunctionDecl* Analyser.instantiateTemplateFunction(Analyser* ma, CallExpr* ca
analyser.free();

if (ma.has_error) return nil;

u16 instance_idx = ma.mod.addInstance(fd, templateType, instance);
instance.setTemplateInstanceIdx(instance_idx);
char[64] name;
create_template_name(name, d.getName(), instance_idx);
instance.setInstanceName(ma.astPool.addStr(name, true));
}
call.setTemplateIdx(instance.getTemplateInstanceIdx());

return instance;
}

Expand Down
2 changes: 2 additions & 0 deletions analyser/module_analyser_expr.c2
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ fn QualType Analyser.analyseExprInner(Analyser* ma, Expr** e_ptr, u32 side) {
return d.getType();
case Type:
break;
case Template:
return ma.analyseTemplateExpr(e_ptr);
case Call:
return ma.analyseCallExpr(e_ptr);
case InitList:
Expand Down
30 changes: 18 additions & 12 deletions analyser/module_analyser_function.c2
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,15 @@ import scope;
// Note: only analyses prototype + args, not the function body
fn void Analyser.analyseFunction(Analyser* ma, FunctionDecl* fd) {
if (fd.isTemplate()) {
// do analyze template name (eg X) for name clash
ma.scope.checkGlobalSymbol(fd.getTemplateNameIdx(), fd.getTemplateLoc());
// do analyze template names (eg X) for name clash
const TemplateSpec* spec = fd.getTemplateSpec();
if (spec) {
u32 len = spec.getTemplateLen();
const TemplateVar* vars = spec.getTemplateVars();
for (u32 i = 0; i < len; i++) {
ma.scope.checkGlobalSymbol(vars[i].name, vars[i].loc);
}
}

// check rtype for array-type
TypeRef* rtype = fd.getReturnTypeRef();
Expand Down Expand Up @@ -128,16 +135,15 @@ fn void Analyser.analyseFunction(Analyser* ma, FunctionDecl* fd) {
bool is_typefn = false;
if (num_params && fd.hasPrefix()) {
// check if SF if first arg is (const) Struct* or (const) Struct
// Note: use TypeRef, since it's faster to check
const Ref* prefix = fd.getPrefix();
const Decl* pd = prefix.decl;
assert(pd);
QualType prefixType = pd.getType();

TypeRef* ref = params[0].getTypeRef();
const Ref* param_ref = ref.getUser();
// Note: for enum types it can be the Type or a pointer to that type
bool is_non_static = ((param_ref && param_ref.decl == prefix.decl) || ref.isPointerTo(prefixType.getIndex()));
// Note: use TypeRef, since it's simpler to check
const Ref* func_prefix = fd.getPrefix();
const TypeRef* arg_ref = params[0].getTypeRef();
const Ref* user = arg_ref.getUser();
bool is_non_static = (user &&
user.name_idx == func_prefix.name_idx &&
arg_ref.getNumPointers() <= 1 &&
!arg_ref.hasPrefix() &&
!arg_ref.isTemplate());
if (is_non_static) {
fd.setCallKind(CallKind.TypeFunc);
is_typefn = true;
Expand Down
1 change: 1 addition & 0 deletions analyser/module_analyser_member.c2
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ fn QualType Analyser.analyseMemberExpr(Analyser* ma, Expr** e_ptr, u32 side) {
EnumTypeDecl* etd = et.getDecl();

// check if constant/enum-function (by first casing)
// TODO: incorrect for Enum.Const.min
const char* last = m.getLastMemberName();
if (ctype.isupper(last[0]) || name_idx == ma.min_idx || name_idx == ma.max_idx) { // search for constants
if (valtype != ValType.NValue) { // variable of Enum type (eg Enum a; a.x)
Expand Down
19 changes: 15 additions & 4 deletions analyser/module_analyser_struct.c2
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,17 @@ import name_vector local;
import size_analyser;

fn void Analyser.analyseStructType(Analyser* ma, StructTypeDecl* d) {
if (d.isTemplate()) {
// do analyze template names (eg X) for name clash
const TemplateSpec* spec = d.getTemplateSpec();
u32 len = spec.getTemplateLen();
const TemplateVar* vars = spec.getTemplateVars();
for (u32 i = 0; i < len; i++) {
ma.scope.checkGlobalSymbol(vars[i].name, vars[i].loc);
}
return; // only analyse on instantiation
}

if (d.isOpaque()) {
ma.checkStack[ma.checkIndex-1].usedPublic = false;
ma.usedPublic = false;
Expand Down Expand Up @@ -194,10 +205,11 @@ fn void Analyser.analyseStructNames(Analyser* ma, StructTypeDecl* d, NameVector*
if (names.find(name_idx, &old_index)) {
ma.error(member.getLoc(), "duplicate struct/union member '%s'", member.getName());
ma.note(locs.get(old_index), "previous declaration is here");
return;
//return;
} else {
names.add(name_idx);
locs.add(member.getLoc());
}
names.add(name_idx);
locs.add(member.getLoc());

if (member.isStructType()) {
NameVector sub_names.init(sub.getNumMembers());
Expand All @@ -210,4 +222,3 @@ fn void Analyser.analyseStructNames(Analyser* ma, StructTypeDecl* d, NameVector*
}
}


Loading