Commits

Iain Buclaw committed d23bab6

New functions build_d_decl_lang_specific, d_mark_exp_read. Added support for -Wunused-variable, WIP -Wunused-but-set-variable.

Comments (0)

Files changed (8)

     }
     else
     {   // Lazy arguments: exp should already be a delegate
-        return exp->toElem(this);
+        tree exp_tree = exp->toElem(this);
+        return exp_tree;
     }
 }
 
 }
 
 
+tree
+IRState::addressOf(tree exp)
+{
+    tree t, ptrtype;
+    tree exp_type = TREE_TYPE(exp);
+    d_mark_addressable(exp);
+
+    // Gimplify doesn't like &(*(ptr-to-array-type)) with static arrays
+    if (TREE_CODE(exp) == INDIRECT_REF)
+    {
+        t = TREE_OPERAND(exp, 0);
+        ptrtype = build_pointer_type(exp_type);
+        t = nop(t, ptrtype);
+    }
+    else
+    {   /* Just convert string literals (char[]) to C-style strings (char *), otherwise
+           the latter method (char[]*) causes conversion problems during gimplification. */
+        if (TREE_CODE (exp) == STRING_CST)
+        {
+            ptrtype = build_pointer_type(TREE_TYPE(exp_type));
+        }
+        /* Special case for va_list. The backends will be expecting a pointer to vatype,
+         * but some targets use an array. So fix it.  */
+        else if (TYPE_MAIN_VARIANT(exp_type) == TYPE_MAIN_VARIANT(va_list_type_node))
+        {
+            if (TREE_CODE(TYPE_MAIN_VARIANT(exp_type)) == ARRAY_TYPE)
+                ptrtype = build_pointer_type(TREE_TYPE(exp_type));
+            else
+                ptrtype = build_pointer_type(exp_type);
+        }
+        else
+            ptrtype = build_pointer_type(exp_type);
+
+        t = build1(ADDR_EXPR, ptrtype, exp);
+    }
+    if (TREE_CODE(exp) == FUNCTION_DECL)
+        TREE_NO_TRAMPOLINE(t) = 1;
+
+    return t;
+}
+
+
 void
 IRState::startCond(Statement * stmt, tree t_cond)
 {
     // ** Various expressions
     tree toElemLvalue(Expression * e);
 
-    static tree addressOf(tree exp)
-    {
-        tree t, ptrtype;
-        tree exp_type = TREE_TYPE(exp);
-        d_mark_addressable(exp);
-
-        // Gimplify doesn't like &(*(ptr-to-array-type)) with static arrays
-        if (TREE_CODE(exp) == INDIRECT_REF)
-        {
-            t = TREE_OPERAND(exp, 0);
-            ptrtype = build_pointer_type(exp_type);
-            t = nop(t, ptrtype);
-        }
-        else
-        {   /* Just convert string literals (char[]) to C-style strings (char *), otherwise
-               the latter method (char[]*) causes conversion problems during gimplification. */
-            if (TREE_CODE (exp) == STRING_CST)
-            {
-                ptrtype = build_pointer_type(TREE_TYPE(exp_type));
-            }
-            /* Special case for va_list. The backends will be expecting a pointer to vatype,
-               but some targets use an array. So fix it.  */
-            else if (TYPE_MAIN_VARIANT(exp_type) == TYPE_MAIN_VARIANT(va_list_type_node))
-            {
-                if (TREE_CODE(TYPE_MAIN_VARIANT(exp_type)) == ARRAY_TYPE)
-                    ptrtype = build_pointer_type(TREE_TYPE(exp_type));
-                else
-                    ptrtype = build_pointer_type(exp_type);
-            }
-            else
-                ptrtype = build_pointer_type(exp_type);
-
-            t = build1(ADDR_EXPR, ptrtype, exp);
-        }
-        if (TREE_CODE(exp) == FUNCTION_DECL)
-            TREE_NO_TRAMPOLINE(t) = 1;
-
-        return t;
-    }
-
     static tree addressOf(Dsymbol *d)
     {
         return addressOf(d->toSymbol()->Stree);
     }
 
+    static tree addressOf(tree exp);
+
     /* Cast exp (which should be a pointer) to TYPE* and then indirect.  The
        back-end requires this cast in many cases. */
     static tree indirect(tree exp, tree type)
     }
 
     irs->buildChain(this); // may change irs->chainLink and irs->chainFunc
+    DECL_LANG_SPECIFIC(fn_decl) = build_d_decl_lang_specific(this);
 
     if (vresult)
         irs->emitLocalVar(vresult);
                 if (int_size_in_bytes(boolean_type_node) == 1)
                     ctype = boolean_type_node;
                 else
-                {
-                    ctype = make_unsigned_type(1);
-                    TREE_SET_CODE(ctype, BOOLEAN_TYPE);
-                    gcc_assert(int_size_in_bytes(ctype) == 1);
-                    dkeep(ctype);
-                }
+                    ctype = d_boolean_type_node;
                 break;
             case Tchar:
                 ctype = d_char_type_node;
     d_null_pointer = convert(ptr_type_node, integer_zero_node);
 
     // %% D variant types of Ctypes.
+    d_boolean_type_node = make_unsigned_type(1);
+    TREE_SET_CODE(d_boolean_type_node, BOOLEAN_TYPE);
+
     d_char_type_node = build_variant_type_copy(unsigned_intQI_type_node);
     d_wchar_type_node = build_variant_type_copy(unsigned_intHI_type_node);
     d_dchar_type_node = build_variant_type_copy(unsigned_intSI_type_node);
 }
 
 
-extern "C" void pushlevel PARAMS ((int));
-extern "C" tree poplevel PARAMS ((int, int, int));
-extern "C" void set_block PARAMS ((tree));
-extern "C" void insert_block PARAMS ((tree));
-
 void IRBase::startScope()
 {
     unsigned * p_count = new unsigned;
 
     tree t_body = popStatementList();
     addExp(build3(BIND_EXPR, void_type_node,
-               BLOCK_VARS( block ), t_body, block));
+           BLOCK_VARS(block), t_body, block));
 
     // Because we used set_block, the popped level/block is not automatically recorded
     insert_block(block);
        Each user-declared variable will have a binding contour that begins
        where the variable is declared and ends at it's containing scope.
     */
-    Array      scopes; // of unsigned*
+    Array scopes; // of unsigned*
 
     void startScope();
     void endScope();
 /* True if the symbol has been marked "static const".  */
 #define D_DECL_READONLY_STATIC(NODE) (DECL_LANG_FLAG_3(NODE))
 
+/* True if the decl has been used except for being set.  */
+#if D_GCC_VER >= 46
+#define D_DECL_READ(NODE) (DECL_READ_P(NODE))
+#else
+#define D_DECL_READ(NODE) (DECL_LANG_FLAG_4(NODE))
+#endif
+
 /* The D front-end does not use the 'binding level' system for a symbol table,
    It is only needed to get debugging information for local variables and
    otherwise support the backend. */
     DTI_VOID_ZERO,
     DTI_VTBL_PTR_TYPE,
 
+    DTI_BOOL_TYPE,
     DTI_CHAR_TYPE,
     DTI_WCHAR_TYPE,
     DTI_DCHAR_TYPE,
 #define d_null_pointer                  d_global_trees[DTI_NULL_PTR]
 #define d_void_zero_node                d_global_trees[DTI_VOID_ZERO]
 #define d_vtbl_ptr_type_node            d_global_trees[DTI_VTBL_PTR_TYPE]
+#define d_boolean_type_node             d_global_trees[DTI_BOOL_TYPE]
 #define d_char_type_node                d_global_trees[DTI_CHAR_TYPE]
 #define d_dchar_type_node               d_global_trees[DTI_DCHAR_TYPE]
 #define d_wchar_type_node               d_global_trees[DTI_WCHAR_TYPE]
 /* In d-lang.cc.  These are called through function pointers
    and do not need to be "extern C". */
 extern bool d_mark_addressable PARAMS ((tree));
+extern void d_mark_exp_read PARAMS ((tree));
 extern tree d_truthvalue_conversion PARAMS ((tree));
 extern tree d_convert_basic PARAMS ((tree, tree));
 extern void d_init_exceptions PARAMS ((void));
 extern Module * d_gcc_get_output_module();
 
 extern struct lang_type * build_d_type_lang_specific(Type * t);
+extern struct lang_decl * build_d_decl_lang_specific(Declaration * d);
 
 /* In asmstmt.cc */
 struct IRState;
 tree d_build_decl(enum tree_code code, tree name, tree type);
 void dkeep(tree t);
 
+int global_bindings_p PARAMS ((void));
+void insert_block PARAMS ((tree));
+void set_block PARAMS ((tree));
+tree getdecls PARAMS ((void));
+
+
 /* In d-builtins.c */
 extern void d_init_builtins PARAMS ((void));
 extern const struct attribute_spec d_common_attribute_table[];
     switch (code)
     {
         case MODIFY_EXPR:
-        {
-            /* If the back end isn't clever enough to know that the lhs and rhs
+        {   /* If the back end isn't clever enough to know that the lhs and rhs
                types are the same, add an explicit conversion.  */
             tree op0 = TREE_OPERAND (*expr_p, 0);
             tree op1 = TREE_OPERAND (*expr_p, 1);
     switch (code)
     {
         case MODIFY_EXPR:
-        {
-            /* If the back end isn't clever enough to know that the lhs and rhs
+        {   /* If the back end isn't clever enough to know that the lhs and rhs
                types are the same, add an explicit conversion.  */
             tree op0 = TREE_OPERAND (*expr_p, 0);
             tree op1 = TREE_OPERAND (*expr_p, 1);
         default:
             return GS_UNHANDLED;
     }
-    return GS_UNHANDLED;
 }
 #endif
 
 }
 
 
+/* Mark EXP as read, not just set, for set but not used -Wunused
+   warning purposes.  */
+
+void
+d_mark_exp_read (tree exp)
+{
+    switch (TREE_CODE (exp))
+    {
+        case VAR_DECL:
+        case PARM_DECL:
+            D_DECL_READ (exp) = 1;
+            break;
+
+        case ARRAY_REF:
+        case COMPONENT_REF:
+        case MODIFY_EXPR:
+        case REALPART_EXPR:
+        case IMAGPART_EXPR:
+        case NOP_EXPR:   
+        case CONVERT_EXPR:
+        case ADDR_EXPR:
+            d_mark_exp_read (TREE_OPERAND (exp, 0));
+            break;
+
+        case COMPOUND_EXPR:
+            d_mark_exp_read (TREE_OPERAND (exp, 1));
+            break;
+
+        default:
+            break;
+    }
+}
+
 
 tree
 d_type_for_mode (enum machine_mode mode, int unsignedp)
 }
 
 
-extern "C" void pushlevel PARAMS ((int));
-extern "C" tree poplevel PARAMS ((int, int, int));
-extern "C" int global_bindings_p PARAMS ((void));
-extern "C" void insert_block PARAMS ((tree));
-extern "C" void set_block PARAMS ((tree));
-extern "C" tree getdecls PARAMS ((void));
-
-
 struct binding_level * current_binding_level;
 struct binding_level * global_binding_level;
 
     if (reverse)
         decls = nreverse(decls);
 
-    if ( level->this_block )
+    if (level->this_block)
         block = level->this_block;
     else if (keep || routinebody)
         block = make_node(BLOCK);
     else
         block = NULL_TREE;
 
-    if (block) {
-        BLOCK_VARS( block ) = routinebody ? NULL_TREE : decls;
-        BLOCK_SUBBLOCKS( block ) = level->blocks;
+    if (block)
+    {
+        BLOCK_VARS(block) = routinebody ? NULL_TREE : decls;
+        BLOCK_SUBBLOCKS(block) = level->blocks;
         // %% need this for when insert_block is called by backend... or make
         // insert_block do it's work elsewere
         // BLOCK_SUBBLOCKS( block ) = level->blocks;
     if (routinebody)
         DECL_INITIAL (current_function_decl) = block;
     else if (block)
-        {
-            // Original logic was: If this block was created by this poplevel
-            // call and not and earlier set_block, insert it into the parent's
-            // list of blocks.  Blocks created with set_block have to be
-            // inserted with insert_block.
-            //
-            // For D, currently always using set_block/insert_block
-            if (!level->this_block)
-                current_binding_level->blocks = chainon (current_binding_level->blocks, block);
-        }
+    {
+        // Original logic was: If this block was created by this poplevel
+        // call and not and earlier set_block, insert it into the parent's
+        // list of blocks.  Blocks created with set_block have to be
+        // inserted with insert_block.
+        //
+        // For D, currently always using set_block/insert_block
+        if (!level->this_block)
+            current_binding_level->blocks = chainon (current_binding_level->blocks, block);
+    }
     /* If we did not make a block for the level just exited, any blocks made for inner
        levels (since they cannot be recorded as subblocks in that level) must be
        carried forward so they will later become subblocks of something else. */
     else if (level->blocks)
         current_binding_level->blocks = chainon (current_binding_level->blocks, level->blocks);
+
     if (block)
+    {
         TREE_USED (block) = 1;
+
+        /* Warnings for unused variables.  */
+        for (tree t = BLOCK_VARS (block); t != NULL_TREE; t = TREE_CHAIN (t))
+        {
+            gcc_assert(TREE_CODE (t) == VAR_DECL);
+            if ((!TREE_USED (t) /*|| !D_DECL_READ(t)*/) //%% TODO
+                && !TREE_NO_WARNING (t)
+                && DECL_NAME (t)
+                && !DECL_ARTIFICIAL (t))
+            {
+                if (!TREE_USED (t))
+                    warning (OPT_Wunused_variable, "unused variable %q+D", t);
+                else if (DECL_CONTEXT (t) == current_function_decl)
+                {
+#if D_GCC_VER >= 46
+                    warning_at (DECL_SOURCE_LOCATION (t),
+                                OPT_Wunused_but_set_variable, "variable %qD set but not used", t);
+#elif D_GCC_VER >= 44
+                    warning_at (DECL_SOURCE_LOCATION (t),
+                                OPT_Wunused_variable, "variable %qD set but not used", t);
+#else
+                    warning (OPT_Wunused_variable, "variable %qD set but not used", t);
+#endif
+                }
+            }
+        }
+    }
     return block;
 }
 
 
     // %% probably  should be cur_irs->getDeclContext()
     // %% should only be for variables OR, should also use TRANSLATION_UNIT for toplevel..
-    if ( DECL_CONTEXT( decl ) == NULL_TREE )
-        DECL_CONTEXT( decl ) = current_function_decl; // could be NULL_TREE (top level) .. hmm. // hm.m.
+    if (DECL_CONTEXT(decl) == NULL_TREE)
+        DECL_CONTEXT(decl) = current_function_decl; // could be NULL_TREE (top level) .. hmm. // hm.m.
 
     /* Put decls on list in reverse order. We will reverse them later if necessary. */
     TREE_CHAIN (decl) = current_binding_level->names;
     return l;
 }
 
+struct lang_decl *
+build_d_decl_lang_specific(Declaration * d)
+{
+    struct lang_decl * l;
+    unsigned sz = sizeof(struct lang_decl);
+#if D_GCC_VER >= 46
+    l = (struct lang_decl *) ggc_alloc_cleared_atomic(sz);
+#else
+    l = (struct lang_decl *) ggc_alloc_cleared(sz);
+#endif
+    l->d_decl = d;
+    return l;
+}
+
+
+// This preserves tree we create from the garbage collector.
 tree d_keep_list = NULL_TREE;
 
 void
 static tree
 d_build_eh_type_type(tree type)
 {
-    TypeClass * d_type = (TypeClass *) IRState::getDType(type);
+    TypeClass * d_type = (TypeClass *) gen.getDType(type);
     gcc_assert(d_type);
     d_type = (TypeClass *) d_type->toBasetype();
     gcc_assert(d_type->ty == Tclass);
-    return IRState::addressOf(d_type->sym->toSymbol()->Stree);
+    return gen.addressOf(d_type->sym->toSymbol()->Stree);
 }
 
 void
 /* True if the symbol has been marked "static const".  */
 #define D_DECL_READONLY_STATIC(NODE) (DECL_LANG_FLAG_3(NODE))
 
+/* True if the decl has been used except for being set.  */
+#define D_DECL_READ(NODE) (DECL_LANG_FLAG_4(NODE))
+
 /* The D front-end does not use the 'binding level' system for a symbol table,
    It is only needed to get debugging information for local variables and
    otherwise support the backend. */
     DTI_VOID_ZERO,
     DTI_VTBL_PTR_TYPE,
 
+    DTI_BOOL_TYPE,
     DTI_CHAR_TYPE,
     DTI_WCHAR_TYPE,
     DTI_DCHAR_TYPE,
 #define d_null_pointer                  d_global_trees[DTI_NULL_PTR]
 #define d_void_zero_node                d_global_trees[DTI_VOID_ZERO]
 #define d_vtbl_ptr_type_node            d_global_trees[DTI_VTBL_PTR_TYPE]
+#define d_boolean_type_node             d_global_trees[DTI_BOOL_TYPE]
 #define d_char_type_node                d_global_trees[DTI_CHAR_TYPE]
 #define d_dchar_type_node               d_global_trees[DTI_DCHAR_TYPE]
 #define d_wchar_type_node               d_global_trees[DTI_WCHAR_TYPE]
 /* In d-lang.cc.  These are called through function pointers
    and do not need to be "extern C". */
 extern bool d_mark_addressable PARAMS ((tree));
+extern void d_mark_exp_read PARAMS ((tree));
 extern tree d_truthvalue_conversion PARAMS ((tree));
 extern tree d_convert_basic PARAMS ((tree, tree));
 extern void d_init_exceptions PARAMS ((void));
 extern Module * d_gcc_get_output_module();
 
 extern struct lang_type * build_d_type_lang_specific(Type * t);
+extern struct lang_decl * build_d_decl_lang_specific(Declaration * d);
 
 /* In asmstmt.cc */
 struct IRState;
 tree d_build_decl(enum tree_code code, tree name, tree type);
 void dkeep(tree t);
 
+int global_bindings_p PARAMS ((void));
+void insert_block PARAMS ((tree));
+void set_block PARAMS ((tree));
+tree getdecls PARAMS ((void));
+
+
 #ifdef D_USE_MAPPED_LOCATION
 tree d_build_decl_loc(location_t loc, enum tree_code code, tree name, tree type);
 #else