1 1.1 mrg /** 2 1.1 mrg * Contains semantic routines specific to ImportC 3 1.1 mrg * 4 1.1 mrg * Specification: C11 5 1.1 mrg * 6 1.1 mrg * Copyright: Copyright (C) 2021-2022 by The D Language Foundation, All Rights Reserved 7 1.1 mrg * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) 8 1.1 mrg * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 9 1.1 mrg * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/importc.d, _importc.d) 10 1.1 mrg * Documentation: https://dlang.org/phobos/dmd_importc.html 11 1.1 mrg * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/importc.d 12 1.1 mrg */ 13 1.1 mrg 14 1.1 mrg module dmd.importc; 15 1.1 mrg 16 1.1 mrg import core.stdc.stdio; 17 1.1 mrg 18 1.1 mrg import dmd.astenums; 19 1.1 mrg import dmd.dcast; 20 1.1 mrg import dmd.declaration; 21 1.1 mrg import dmd.dscope; 22 1.1 mrg import dmd.dsymbol; 23 1.1 mrg import dmd.expression; 24 1.1 mrg import dmd.expressionsem; 25 1.1 mrg import dmd.identifier; 26 1.1 mrg import dmd.init; 27 1.1 mrg import dmd.mtype; 28 1.1 mrg import dmd.tokens; 29 1.1 mrg import dmd.typesem; 30 1.1 mrg 31 1.1 mrg /************************************** 32 1.1 mrg * C11 does not allow array or function parameters. 33 1.1 mrg * Hence, adjust those types per C11 6.7.6.3 rules. 34 1.1 mrg * Params: 35 1.1 mrg * t = parameter type to adjust 36 1.1 mrg * sc = context 37 1.1 mrg * Returns: 38 1.1 mrg * adjusted type 39 1.1 mrg */ 40 1.1 mrg Type cAdjustParamType(Type t, Scope* sc) 41 1.1 mrg { 42 1.1 mrg if (!(sc.flags & SCOPE.Cfile)) 43 1.1 mrg return t; 44 1.1 mrg 45 1.1 mrg Type tb = t.toBasetype(); 46 1.1 mrg 47 1.1 mrg /* C11 6.7.6.3-7 array of T is converted to pointer to T 48 1.1 mrg */ 49 1.1 mrg if (auto ta = tb.isTypeDArray()) 50 1.1 mrg { 51 1.1 mrg t = ta.next.pointerTo(); 52 1.1 mrg } 53 1.1 mrg else if (auto ts = tb.isTypeSArray()) 54 1.1 mrg { 55 1.1 mrg t = ts.next.pointerTo(); 56 1.1 mrg } 57 1.1 mrg /* C11 6.7.6.3-8 function is converted to pointer to function 58 1.1 mrg */ 59 1.1 mrg else if (tb.isTypeFunction()) 60 1.1 mrg { 61 1.1 mrg t = tb.pointerTo(); 62 1.1 mrg } 63 1.1 mrg return t; 64 1.1 mrg } 65 1.1 mrg 66 1.1 mrg /*********************************************** 67 1.1 mrg * C11 6.3.2.1-3 Convert expression that is an array of type to a pointer to type. 68 1.1 mrg * C11 6.3.2.1-4 Convert expression that is a function to a pointer to a function. 69 1.1 mrg * Params: 70 1.1 mrg * e = ImportC expression to possibly convert 71 1.1 mrg * sc = context 72 1.1 mrg * Returns: 73 1.1 mrg * converted expression 74 1.1 mrg */ 75 1.1 mrg Expression arrayFuncConv(Expression e, Scope* sc) 76 1.1 mrg { 77 1.1 mrg //printf("arrayFuncConv() %s\n", e.toChars()); 78 1.1 mrg if (!(sc.flags & SCOPE.Cfile)) 79 1.1 mrg return e; 80 1.1 mrg 81 1.1 mrg auto t = e.type.toBasetype(); 82 1.1 mrg if (auto ta = t.isTypeDArray()) 83 1.1 mrg { 84 1.1 mrg e = e.castTo(sc, ta.next.pointerTo()); 85 1.1 mrg } 86 1.1 mrg else if (auto ts = t.isTypeSArray()) 87 1.1 mrg { 88 1.1 mrg e = e.castTo(sc, ts.next.pointerTo()); 89 1.1 mrg } 90 1.1 mrg else if (t.isTypeFunction()) 91 1.1 mrg { 92 1.1 mrg e = new AddrExp(e.loc, e); 93 1.1 mrg } 94 1.1 mrg else 95 1.1 mrg return e; 96 1.1 mrg return e.expressionSemantic(sc); 97 1.1 mrg } 98 1.1 mrg 99 1.1 mrg /**************************************** 100 1.1 mrg * Run semantic on `e`. 101 1.1 mrg * Expression `e` evaluates to an instance of a struct. 102 1.1 mrg * Look up `ident` as a field of that struct. 103 1.1 mrg * Params: 104 1.1 mrg * e = evaluates to an instance of a struct 105 1.1 mrg * sc = context 106 1.1 mrg * id = identifier of a field in that struct 107 1.1 mrg * Returns: 108 1.1 mrg * if successful `e.ident` 109 1.1 mrg * if not then `ErrorExp` and message is printed 110 1.1 mrg */ 111 1.1 mrg Expression fieldLookup(Expression e, Scope* sc, Identifier id) 112 1.1 mrg { 113 1.1 mrg e = e.expressionSemantic(sc); 114 1.1 mrg if (e.isErrorExp()) 115 1.1 mrg return e; 116 1.1 mrg 117 1.1 mrg Dsymbol s; 118 1.1 mrg auto t = e.type; 119 1.1 mrg if (t.isTypePointer()) 120 1.1 mrg { 121 1.1 mrg t = t.isTypePointer().next; 122 1.1 mrg e = new PtrExp(e.loc, e); 123 1.1 mrg } 124 1.1 mrg if (auto ts = t.isTypeStruct()) 125 1.1 mrg s = ts.sym.search(e.loc, id, 0); 126 1.1 mrg if (!s) 127 1.1 mrg { 128 1.1 mrg e.error("`%s` is not a member of `%s`", id.toChars(), t.toChars()); 129 1.1 mrg return ErrorExp.get(); 130 1.1 mrg } 131 1.1 mrg Expression ef = new DotVarExp(e.loc, e, s.isDeclaration()); 132 1.1 mrg return ef.expressionSemantic(sc); 133 1.1 mrg } 134 1.1 mrg 135 1.1 mrg /**************************************** 136 1.1 mrg * C11 6.5.2.1-2 137 1.1 mrg * Apply C semantics to `E[I]` expression. 138 1.1 mrg * E1[E2] is lowered to *(E1 + E2) 139 1.1 mrg * Params: 140 1.1 mrg * ae = ArrayExp to run semantics on 141 1.1 mrg * sc = context 142 1.1 mrg * Returns: 143 1.1 mrg * Expression if this was a C expression with completed semantic, null if not 144 1.1 mrg */ 145 1.1 mrg Expression carraySemantic(ArrayExp ae, Scope* sc) 146 1.1 mrg { 147 1.1 mrg if (!(sc.flags & SCOPE.Cfile)) 148 1.1 mrg return null; 149 1.1 mrg 150 1.1 mrg auto e1 = ae.e1.expressionSemantic(sc); 151 1.1 mrg 152 1.1 mrg assert(ae.arguments.length == 1); 153 1.1 mrg Expression e2 = (*ae.arguments)[0]; 154 1.1 mrg 155 1.1 mrg /* CTFE cannot do pointer arithmetic, but it can index arrays. 156 1.1 mrg * So, rewrite as an IndexExp if we can. 157 1.1 mrg */ 158 1.1 mrg auto t1 = e1.type.toBasetype(); 159 1.1 mrg if (t1.isTypeDArray() || t1.isTypeSArray()) 160 1.1 mrg { 161 1.1 mrg e2 = e2.expressionSemantic(sc).arrayFuncConv(sc); 162 1.1 mrg // C doesn't do array bounds checking, so `true` turns it off 163 1.1 mrg return new IndexExp(ae.loc, e1, e2, true).expressionSemantic(sc); 164 1.1 mrg } 165 1.1 mrg 166 1.1 mrg e1 = e1.arrayFuncConv(sc); // e1 might still be a function call 167 1.1 mrg e2 = e2.expressionSemantic(sc); 168 1.1 mrg auto t2 = e2.type.toBasetype(); 169 1.1 mrg if (t2.isTypeDArray() || t2.isTypeSArray()) 170 1.1 mrg { 171 1.1 mrg return new IndexExp(ae.loc, e2, e1, true).expressionSemantic(sc); // swap operands 172 1.1 mrg } 173 1.1 mrg 174 1.1 mrg e2 = e2.arrayFuncConv(sc); 175 1.1 mrg auto ep = new PtrExp(ae.loc, new AddExp(ae.loc, e1, e2)); 176 1.1 mrg return ep.expressionSemantic(sc); 177 1.1 mrg } 178 1.1 mrg 179 1.1 mrg /****************************************** 180 1.1 mrg * Determine default initializer for const global symbol. 181 1.1 mrg */ 182 1.1 mrg void addDefaultCInitializer(VarDeclaration dsym) 183 1.1 mrg { 184 1.1 mrg //printf("addDefaultCInitializer() %s\n", dsym.toChars()); 185 1.1 mrg if (!(dsym.storage_class & (STC.static_ | STC.gshared))) 186 1.1 mrg return; 187 1.1 mrg if (dsym.storage_class & (STC.extern_ | STC.field | STC.in_ | STC.foreach_ | STC.parameter | STC.result)) 188 1.1 mrg return; 189 1.1 mrg 190 1.1 mrg Type t = dsym.type; 191 1.1 mrg if (t.isTypeSArray() && t.isTypeSArray().isIncomplete()) 192 1.1 mrg { 193 1.1 mrg dsym._init = new VoidInitializer(dsym.loc); 194 1.1 mrg return; // incomplete arrays will be diagnosed later 195 1.1 mrg } 196 1.1 mrg 197 1.1 mrg if (t.isMutable()) 198 1.1 mrg return; 199 1.1 mrg 200 1.1 mrg auto e = dsym.type.defaultInit(dsym.loc, true); 201 1.1 mrg dsym._init = new ExpInitializer(dsym.loc, e); 202 1.1 mrg } 203 1.1 mrg 204 1.1 mrg /******************************************** 205 1.1 mrg * Resolve cast/call grammar ambiguity. 206 1.1 mrg * Params: 207 1.1 mrg * e = expression that might be a cast, might be a call 208 1.1 mrg * sc = context 209 1.1 mrg * Returns: 210 1.1 mrg * null means leave as is, !=null means rewritten AST 211 1.1 mrg */ 212 1.1 mrg Expression castCallAmbiguity(Expression e, Scope* sc) 213 1.1 mrg { 214 1.1 mrg Expression* pe = &e; 215 1.1 mrg 216 1.1 mrg while (1) 217 1.1 mrg { 218 1.1 mrg // Walk down the postfix expressions till we find a CallExp or something else 219 1.1 mrg switch ((*pe).op) 220 1.1 mrg { 221 1.1 mrg case EXP.dotIdentifier: 222 1.1 mrg pe = &(*pe).isDotIdExp().e1; 223 1.1 mrg continue; 224 1.1 mrg 225 1.1 mrg case EXP.plusPlus: 226 1.1 mrg case EXP.minusMinus: 227 1.1 mrg pe = &(*pe).isPostExp().e1; 228 1.1 mrg continue; 229 1.1 mrg 230 1.1 mrg case EXP.array: 231 1.1 mrg pe = &(*pe).isArrayExp().e1; 232 1.1 mrg continue; 233 1.1 mrg 234 1.1 mrg case EXP.call: 235 1.1 mrg auto ce = (*pe).isCallExp(); 236 1.1 mrg if (ce.e1.parens) 237 1.1 mrg { 238 1.1 mrg ce.e1 = expressionSemantic(ce.e1, sc); 239 1.1 mrg if (ce.e1.op == EXP.type) 240 1.1 mrg { 241 1.1 mrg const numArgs = ce.arguments ? ce.arguments.length : 0; 242 1.1 mrg if (numArgs >= 1) 243 1.1 mrg { 244 1.1 mrg ce.e1.parens = false; 245 1.1 mrg Expression arg; 246 1.1 mrg foreach (a; (*ce.arguments)[]) 247 1.1 mrg { 248 1.1 mrg arg = arg ? new CommaExp(a.loc, arg, a) : a; 249 1.1 mrg } 250 1.1 mrg auto t = ce.e1.isTypeExp().type; 251 1.1 mrg *pe = arg; 252 1.1 mrg return new CastExp(ce.loc, e, t); 253 1.1 mrg } 254 1.1 mrg } 255 1.1 mrg } 256 1.1 mrg return null; 257 1.1 mrg 258 1.1 mrg default: 259 1.1 mrg return null; 260 1.1 mrg } 261 1.1 mrg } 262 1.1 mrg } 263 1.1 mrg 264 1.1 mrg /******************************************** 265 1.1 mrg * Implement the C11 notion of function equivalence, 266 1.1 mrg * which allows prototyped functions to match K+R functions, 267 1.1 mrg * even though they are different. 268 1.1 mrg * Params: 269 1.1 mrg * tf1 = type of first function 270 1.1 mrg * tf2 = type of second function 271 1.1 mrg * Returns: 272 1.1 mrg * true if C11 considers them equivalent 273 1.1 mrg */ 274 1.1 mrg 275 1.1 mrg bool cFuncEquivalence(TypeFunction tf1, TypeFunction tf2) 276 1.1 mrg { 277 1.1 mrg //printf("cFuncEquivalence()\n %s\n %s\n", tf1.toChars(), tf2.toChars()); 278 1.1 mrg if (tf1.equals(tf2)) 279 1.1 mrg return true; 280 1.1 mrg 281 1.1 mrg if (tf1.linkage != tf2.linkage) 282 1.1 mrg return false; 283 1.1 mrg 284 1.1 mrg // Allow func(void) to match func() 285 1.1 mrg if (tf1.parameterList.length == 0 && tf2.parameterList.length == 0) 286 1.1 mrg return true; 287 1.1 mrg 288 1.1 mrg if (!cTypeEquivalence(tf1.next, tf2.next)) 289 1.1 mrg return false; // function return types don't match 290 1.1 mrg 291 1.1 mrg if (tf1.parameterList.length != tf2.parameterList.length) 292 1.1 mrg return false; 293 1.1 mrg 294 1.1 mrg if (!tf1.parameterList.hasIdentifierList && !tf2.parameterList.hasIdentifierList) // if both are prototyped 295 1.1 mrg { 296 1.1 mrg if (tf1.parameterList.varargs != tf2.parameterList.varargs) 297 1.1 mrg return false; 298 1.1 mrg } 299 1.1 mrg 300 1.1 mrg foreach (i, fparam ; tf1.parameterList) 301 1.1 mrg { 302 1.1 mrg Type t1 = fparam.type; 303 1.1 mrg Type t2 = tf2.parameterList[i].type; 304 1.1 mrg 305 1.1 mrg /* Strip off head const. 306 1.1 mrg * Not sure if this is C11, but other compilers treat 307 1.1 mrg * `void fn(int)` and `fn(const int x)` 308 1.1 mrg * as equivalent. 309 1.1 mrg */ 310 1.1 mrg t1 = t1.mutableOf(); 311 1.1 mrg t2 = t2.mutableOf(); 312 1.1 mrg 313 1.1 mrg if (!t1.equals(t2)) 314 1.1 mrg return false; 315 1.1 mrg } 316 1.1 mrg 317 1.1 mrg //printf("t1: %s\n", tf1.toChars()); 318 1.1 mrg //printf("t2: %s\n", tf2.toChars()); 319 1.1 mrg return true; 320 1.1 mrg } 321 1.1 mrg 322 1.1 mrg /******************************* 323 1.1 mrg * Types haven't been merged yet, because we haven't done 324 1.1 mrg * semantic() yet. 325 1.1 mrg * But we still need to see if t1 and t2 are the same type. 326 1.1 mrg * Params: 327 1.1 mrg * t1 = first type 328 1.1 mrg * t2 = second type 329 1.1 mrg * Returns: 330 1.1 mrg * true if they are equivalent types 331 1.1 mrg */ 332 1.1 mrg bool cTypeEquivalence(Type t1, Type t2) 333 1.1 mrg { 334 1.1 mrg if (t1.equals(t2)) 335 1.1 mrg return true; // that was easy 336 1.1 mrg 337 1.1 mrg if (t1.ty != t2.ty || t1.mod != t2.mod) 338 1.1 mrg return false; 339 1.1 mrg 340 1.1 mrg if (auto tp = t1.isTypePointer()) 341 1.1 mrg return cTypeEquivalence(tp.next, t2.nextOf()); 342 1.1 mrg 343 1.1 mrg if (auto ta = t1.isTypeSArray()) 344 1.1 mrg // Bug: should check array dimension 345 1.1 mrg return cTypeEquivalence(ta.next, t2.nextOf()); 346 1.1 mrg 347 1.1 mrg if (auto ts = t1.isTypeStruct()) 348 1.1 mrg return ts.sym is t2.isTypeStruct().sym; 349 1.1 mrg 350 1.1 mrg if (auto te = t1.isTypeEnum()) 351 1.1 mrg return te.sym is t2.isTypeEnum().sym; 352 1.1 mrg 353 1.1 mrg if (auto tf = t1.isTypeFunction()) 354 1.1 mrg return cFuncEquivalence(tf, tf.isTypeFunction()); 355 1.1 mrg 356 1.1 mrg return false; 357 1.1 mrg } 358