View Issue Details

IDProjectCategoryView StatusLast Update
0000362LDMud 3.3LPC Compiler/Preprocessorpublic2018-01-29 21:57
ReporterGnomi Assigned Tolars 
PrioritynormalSeverityminorReproducibilityalways
Status closedResolutionfixed 
Platformi686OSDebian GNU/LinuxOS Version3.0
Product Version3.3 
Fixed in Version3.3.713 
Summary0000362: Problems with private functions
DescriptionHi,

I looked through my mails for correspondence about this "public fun() shadows private fun()" warning, but came across another bug report and was curious enough to give it a try with the 3.3 driver.

This was fixed in 3.2.9-dev.364/365:
If a program A has a private function F, that is also the name of a simul-efun, and program B inherits A, it can't call the simul-efun anymore but gets the compiler error 'Function F is private'.

The problem I wanted to report (and where I thought, we talked about this in the 3.2 line, but I couldn't find any mails regarding this) is, that private functions are not entirely invisible to inheriting programs (but in my opinion they should be). If the inheriting program has a function that happens to have the same name, it gets a warning 'public programA::fun() shadows private programB::fun()'. This is especially a problem, when we introduce new private functions in the base lib and don't want to grep the whole MUD for it. If you disagree maybe a pragma to turn this warning off would be an option?

Greetings,
Gnomi.
TagsNo tags attached.
Attached Files
prolang.privefun.diff (628 bytes)   
Index: prolang.y
===================================================================
--- prolang.y	(Revision 22)
+++ prolang.y	(Arbeitskopie)
@@ -15084,7 +15084,8 @@
 
                 /* Handle the non-lfun aspects of the identifier */
                 {
-                    if ((n != I_GLOBAL_FUNCTION_OTHER || p->u.global.efun < 0)
+                    if (n != I_GLOBAL_FUNCTION_OTHER
+                     || (p->u.global.efun < 0 && p->u.global.sim_efun < 0)
                      || (fun.flags & (TYPE_MOD_PRIVATE|NAME_HIDDEN)) == 0
                      || (fun.flags & (NAME_UNDEFINED)) != 0
                        )
prolang.privefun.diff (628 bytes)   
prolang.privinh.diff (10,524 bytes)   
Index: src/prolang.y
===================================================================
--- src/prolang.y	(Revision 22)
+++ src/prolang.y	(Arbeitskopie)
@@ -2882,8 +2882,8 @@
 
         funp = FUNCTION(num);
 
-        if ((funp->flags & (NAME_INHERITED|TYPE_MOD_PRIVATE))
-         == (NAME_INHERITED|TYPE_MOD_PRIVATE))
+        if ((funp->flags & (NAME_INHERITED|TYPE_MOD_PRIVATE|NAME_HIDDEN|NAME_UNDEFINED))
+         == (NAME_INHERITED|TYPE_MOD_PRIVATE|NAME_HIDDEN))
         {
             break;
         }
@@ -14876,28 +14876,12 @@
          */
         switch (0) {
         default:
-            /* Test if the function is visible at all.
-             * For this test, 'private nomask' degenerates to 'private'
-             * if we didn't do that, the driver would crash on a second
-             * level inherit (possible on a multiple second-level inherit).
-             * TODO: Find out why it crashes.
+            /* Ignore cross defines.
+             * They are the only complete invisible entries.
              */
-            {
-                funflag_t fflags = fun.flags;
+            if (fun.flags & NAME_CROSS_DEFINED)
+                break;
 
-                if ((fflags & (TYPE_MOD_PRIVATE|TYPE_MOD_NO_MASK))
-                 == (TYPE_MOD_PRIVATE|TYPE_MOD_NO_MASK)
-                   )
-                    fflags &= ~(TYPE_MOD_NO_MASK);
-
-                if ( (fflags & (NAME_HIDDEN|TYPE_MOD_NO_MASK|NAME_UNDEFINED) ) ==
-
-                     (NAME_HIDDEN|TYPE_MOD_NO_MASK) )
-                {
-                    break;
-                }
-            }
-
             /* Visible: create a new identifier for it */
             p = make_global_identifier(get_txt(fun.name), I_TYPE_GLOBAL);
             if (!p)
@@ -14955,7 +14939,6 @@
                         }
                         else if ((fun.flags | type) & TYPE_MOD_VIRTUAL
                               && OldFunction->flags & TYPE_MOD_VIRTUAL
-                          && !((fun.flags | OldFunction->flags) & NAME_HIDDEN)
                           &&    get_function_id(from, i)
   == get_function_id(INHERIT(OldFunction->offset.inherit).prog
                 , n - INHERIT(OldFunction->offset.inherit).function_index_offset
@@ -14972,104 +14955,70 @@
                             cross_define( OldFunction, &fun
                                         , n - current_func_index );
                         }
+                        else if ( (fun.flags & (TYPE_MOD_PRIVATE|NAME_HIDDEN|NAME_UNDEFINED))
+                                    == (TYPE_MOD_PRIVATE|NAME_HIDDEN) )
+                        {
+                            /* There is already one function with this
+                            * name. Ignore the private one, as we
+                            * only need it for useful error messages.
+                            */
+
+                            break;
+                        }
+                        else if ( (OldFunction->flags & (TYPE_MOD_PRIVATE|NAME_HIDDEN|NAME_UNDEFINED))
+                                     == (TYPE_MOD_PRIVATE|NAME_HIDDEN) )
+                        {
+                            /* The old one was invisible, ignore it
+                             * and take this one.
+                             */
+
+                            p->u.global.function = current_func_index;
+                        }
                         else if ( (fun.flags & OldFunction->flags & TYPE_MOD_NO_MASK)
-                             &&  !( (fun.flags|OldFunction->flags) & (TYPE_MOD_PRIVATE|NAME_UNDEFINED) ) )
+                             &&  !( (fun.flags|OldFunction->flags) & NAME_UNDEFINED ) )
                         {
                             yyerrorf(
                               "Illegal to inherit 'nomask' function '%s' twice",
                               get_txt(fun.name));
                         }
                         else if ((   fun.flags & TYPE_MOD_NO_MASK
-                                  || OldFunction->flags & (NAME_HIDDEN|NAME_UNDEFINED|TYPE_MOD_PRIVATE))
-                              && !(fun.flags & (NAME_HIDDEN|NAME_UNDEFINED))
+                                  || OldFunction->flags & NAME_UNDEFINED )
+                              && !(fun.flags & NAME_UNDEFINED)
                                 )
                         {
                             /* This function is visible and existing, but the
                              * inherited one is not, or this one is also nomask:
                              * prefer this one one.
                              */
-                            if (OldFunction->flags & TYPE_MOD_PRIVATE)
-                            {
-                                string_t * oldFrom = NULL;
-
-                                if (OldFunction->flags & NAME_INHERITED)
-                                {
-                                    oldFrom = INHERIT(OldFunction->offset.inherit).prog->name;
-                                }
-
-                                warn_function_shadow( from->name, fun.name
-                                                    , oldFrom, OldFunction->name
-                                                    );
-                            }
-
                             cross_define( &fun, OldFunction
                                         , current_func_index - n );
                             p->u.global.function = current_func_index;
                         }
-                        else if ( (fun.flags & TYPE_MOD_PRIVATE) == 0
-                              ||  (OldFunction->flags & TYPE_MOD_PRIVATE) == 0
-                              ||  ((OldFunction->flags|fun.flags)
-                                   & TYPE_MOD_VIRTUAL) != 0
-                                )
+                        else
                         {
                             /* At least one of the functions is visible
                              * or redefinable: prefer the first one.
-                             * TODO: The whole if-condition is more a kludge,
-                             * TODO:: developed iteratively from .367
-                             * TODO:: through .370. It should be reconsidered,
-                             * TODO:: which of course implies a deeper
-                             * TODO:: analysis of the going-ons here.
                              */
 
-                            /* Warn about private <-> public collisions;
-                             * however public <-> public and private <->
-                             * private are to be expected.
-                             */
-                            string_t * oldFrom = NULL;
-
-                            if (OldFunction->flags & NAME_INHERITED)
-                            {
-                                oldFrom = INHERIT(OldFunction->offset.inherit).prog->name;
-                            }
-
-                            if ((fun.flags & TYPE_MOD_PRIVATE)
-                             && !(OldFunction->flags & TYPE_MOD_PRIVATE))
-                            {
-                                warn_function_shadow( oldFrom, OldFunction->name
-                                                    , from->name, fun.name
-                                                    );
-                            }
-                            else if (!(fun.flags & TYPE_MOD_PRIVATE)
-                                  && (OldFunction->flags & TYPE_MOD_PRIVATE)
-                                )
-                            {
-                                warn_function_shadow( from->name, fun.name
-                                                    , oldFrom, OldFunction->name
-                                                    );
-                            }
-
                             cross_define( OldFunction, &fun
                                         , n - current_func_index );
                         }
                     } /* if (n < first_func_index) */
-                    else if ( !(fun.flags & NAME_CROSS_DEFINED) )
+                    else if ( (fun.flags & (TYPE_MOD_PRIVATE|NAME_HIDDEN|NAME_UNDEFINED)) 
+                                != (TYPE_MOD_PRIVATE|NAME_HIDDEN) )
                     {
                         /* This is the dominant definition in the superclass,
                          * inherit this one.
                          */
 #ifdef DEBUG
-                        /* The definition we picked before should be
-                         * cross-defined to the definition we have now; or
-                         * it should be nominally invisible so we can redefine
-                         * it.
+                        /* The definition we picked before can't be
+                         * cross-defined, because cross-defines won't
+                         * be registered as global identifiers.
+                         * So the previous definition should be
+                         * nominally invisible so we can redefine it.
                          */
-                        if ((   !(FUNCTION(n)->flags & NAME_CROSS_DEFINED)
-                             ||   FUNCTION(n)->offset.func
-                                != MAKE_CROSSDEF_OFFSET(((int32)current_func_index) - n)
-                            )
-                         && ((FUNCTION(n)->flags & TYPE_MOD_PRIVATE) == 0
-                            )
-                           )
+                        if ( (FUNCTION(n)->flags & (TYPE_MOD_PRIVATE|NAME_HIDDEN|NAME_UNDEFINED))
+                                != (TYPE_MOD_PRIVATE|NAME_HIDDEN) )
                         {
                             fatal(
                               "Inconsistent definition of %s() within "
@@ -15363,6 +15312,16 @@
                      && (*flagp & INHERIT_MASK) == inheritc )
                     {
                         funp->offset.inherit = inherit_index;
+
+                        if(funp != funp2)
+                        {
+                            /* I don't think, that this is a wise idea.
+                               Because the function index offset of this
+                               inherit is not correct for this function.
+                            */
+                            yywarnf("Adjusting inherit index because of virtual inherit %.*s!\n",
+                                    (int) from->name->size, from->name->txt);
+                        }
                     }
                     flagp++;
                 }
prolang.privinh.diff (10,524 bytes)   
prolang.privinh.txt (3,274 bytes)   
The first hunk is in define_new_function(). This if-statement ignores
any inherited private function, so that it's not redefined.
But it also ignores any regular function, that was inherited
with the "private functions" modifier (which makes the function
not private for us, but to outsiders). That's why I also
require NAME_HIDDEN to be set. But NAME_HIDDEN is also set,
when it was only a prototype und so I check, that NAME_UNDEFINED
is not set.

Now to the changes in copy_functions():

This function ignored any NAME_HIDDEN, TYPE_MOD_NO_MASK, but
not NAME_UNDEFINED and not TYPE_MOD_PRIVATE functions. As NAME_HIDDEN
are either private functions, prototypes or cross-definitions,
it can only be later, because private functions have TYPE_MOD_PRIVATE
(and "private nomask" becomes "private", so TYPE_MOD_NO_MASK isn't
satisfied anymore) and Prototypes have NAME_UNDEFINED. I replaced
this by a check for NAME_CROSS_DEFINED. (Don't know, why only
nomask cross-definitions are ignored, I think, it should ignore
all cross-definitions.) Btw. if the "'private nomask' degenerates to
'private'"-part wouldn't be there, it would also ignore 'nomask private'
functions und therefore would not cross-define them, if they were virtual
functions. (Why this missing cross-definition crashes, I'll explain later
in the part for copy_variables.)

virtual private functions should also be cross-defined, that's why
I removed the condition for NAME_HIDDEN. (This condition was superflous,
because the last else-if-statement would cross-define them anyway.)

If this function is private, we keep the first definition.
If the previous function was private (TYPE_MOD_PRIVATE, NAME_HIDDEN
because of "private functions inherit" making the function also
TYPE_MOD_PRIVATE, and not NAME_UNDEFINED to get no prototypes, which
are also NAME_HIDDEN), we take the new function. (For the
current function a check for TYPE_MOD_PRIVATE would only be required,
because it doesn't has the "private functions inherit"-problem.
But to make it uniform, I decided to use the same condition for
fun and OldFunction.)

Only then (just before the cross-definitions) there comes the check
for double inheriting 'nomask' functions. Because private functions
were handled before, I removed the check for TYPE_MOD_PRIVATE.
The same for the following checks: I removed the checks for private
functions. So the last if-condition can be omitted completely (we
handled private and virtual functions before).

After that comes the handling of two functions in the same superclass
having the same name. As cross-definitions are handled before,
the original if-statement can be left out. But now we have to check
whether this new function is really the dominant definition and not
just some invisible function.

The last part is about copy_variables() and why it crashes if two
occurrences of the same private virtual function are not cross-defined.
copy_variables would then adjust the inherit index of the second occurrence,
but neither the function index nor the inherit function index offset
can't be adjusted and so the wrong function index in the inherit's
program will be computed and thus lead to a crash. I inserted a warning
(because I maybe wrong), but I think it should be a fatal error.

Greetings,
Gnomi.
prolang.privinh.txt (3,274 bytes)   
prolang.privvirtinh.diff (762 bytes)   
diff -Naur 3.3privinh/src/prolang.y 3.3privvirtinh/src/prolang.y
--- 3.3privinh/src/prolang.y	2005-08-18 15:14:05.000000000 +0200
+++ 3.3privvirtinh/src/prolang.y	2005-11-30 23:21:00.000000000 +0100
@@ -14951,7 +14958,8 @@
                              */
                             OldFunction->flags |= fun.flags &
                                 (TYPE_MOD_PUBLIC|TYPE_MOD_NO_MASK);
-                            OldFunction->flags &= fun.flags | ~TYPE_MOD_STATIC;
+                            OldFunction->flags &= fun.flags |
+				~(TYPE_MOD_STATIC|TYPE_MOD_PRIVATE|TYPE_MOD_PROTECTED|NAME_HIDDEN);
                             cross_define( OldFunction, &fun
                                         , n - current_func_index );
                         }
prolang.privvirtinh.diff (762 bytes)   

Activities

lars

2005-02-02 22:34

reporter   ~0000324

I am not sure you want that. Consider this setup:

-- a.c ---
private sub() { debug_message("a::sub()\n"); }
void main() { sub(); }

-- b.c ---
public sub() { debug_message("b::sub()\n"); }

-- c.c ---
inherit "a";
inherit "b";
------

load_object("c")->main() will now print "b::sub()", not "a::sub()", and without the warning ("public b::sub() shadows private a::sub()") you'd have a hard time finding this.


Is this a flaw in the way the driver handles inherits? Maybe, but as far as I can see this has been the official behavior since the times of yore (3.2.1):

                        else if (( fun.flags & TYPE_MOD_NO_MASK
                                  || OldFunction->flags & (NAME_HIDDEN|NAME_UNDEFINED|TYPE_MOD_PRIVATE))
                              && !(fun.flags & (NAME_HIDDEN|NAME_UNDEFINED))
                                )
                        {
                            /* This function is visible and existing, but the
                             * inherited one is not, or this one is also nomask:
                             * prefer this one one.
                             */
                            if (OldFunction->flags & TYPE_MOD_PRIVATE)
                            {
                                string_t * oldFrom = NULL;

                                if (OldFunction->flags & NAME_INHERITED)
                                {
                                    oldFrom = INHERIT(OldFunction->offset.inherit).prog->name;
                                }

                                warn_function_shadow( from->name, fun.name
                                                    , oldFrom, OldFunction->name
                                                    );
                            }

                            cross_define( &fun, OldFunction
                                        , current_func_index - n );
                            p->u.global.function = current_func_index;
                        }

Gnomi

2005-02-03 01:34

manager   ~0000325

But the following setup has a contrary behavior:

-- a.c ---
private void sub() { debug_message("a::sub()\n"); }
void main() { sub(); }

-- b.c ---
inherit "a";
public void sub() { debug_message("b::sub()\n"); }


load_object("b")->main() will print "a::sub()", so I think, the behavior you describe is a bug in the inheritance handling. (It is not intuitive and - looking at both examples - inconsistent.) Why should one want this behaviour?

Greetings,
Gnomi

lars

2005-02-03 09:19

reporter   ~0000326

Oh, I don't think anybody ever explicitely 'wanted' that behavior - it just happened.

Gnomi

2005-02-03 09:30

manager   ~0000327

Okay, I rephrase. ;-)

What kind of code could possibly take advantage of this behavior? (If it is the official behavior, but nobody uses it, a change is not a problem. If it is used, I'd like to see that code. Or better not...)

Bardioc

2005-03-02 11:39

reporter   ~0000352

I agree with Gnomi,

I checked our Mudlib about this issue and I did not find any advantage or use of this 'feature' so I would prefer to change the inheritance as soon as possible so that in lars' example load_object("c")->main() STILL prints "a::sub()" as it is supposed to be.

Gnomi

2005-08-15 14:18

manager   ~0000381

I attached a diff that solves the first problem (private function overrides a simul-efun).

Gnomi

2005-08-18 06:52

manager   ~0000382

I uploaded a second diff for the 'private functions are not entirely invisible' problem and an explanation for the changes. The diff is pretty experimental, because I can't say I understood all aspects of the code, but I tested it in our TestMUD and it didn't cause a crash.

Gnomi

2005-11-30 17:09

manager   ~0000430

I uploaded a third diff (prolang.privvirtinh.diff) which fixes a problem with a virtual inherit that is inherited twice - one of which with 'private functions'. The driver didn't calculate the best visibility of both occurrences correctly. If one occurrence is private, the function will be private in the program, although the second occurrence may have normal visibility. The posted diff fixes this.

lars

2005-12-04 21:24

reporter   ~0000443

It took me longer that it should, but I have incorporated the diffs now.

Issue History

Date Modified Username Field Change
2005-02-02 04:19 Gnomi New Issue
2005-02-02 22:34 lars Note Added: 0000324
2005-02-03 01:34 Gnomi Note Added: 0000325
2005-02-03 09:20 lars Note Added: 0000326
2005-02-03 09:30 Gnomi Note Added: 0000327
2005-03-02 11:39 Bardioc Note Added: 0000352
2005-08-15 14:17 Gnomi File Added: prolang.privefun.diff
2005-08-15 14:18 Gnomi Note Added: 0000381
2005-08-18 06:41 Gnomi File Added: prolang.privinh.diff
2005-08-18 06:41 Gnomi File Added: prolang.privinh.txt
2005-08-18 06:52 Gnomi Note Added: 0000382
2005-11-30 16:58 Gnomi File Added: prolang.privvirtinh.diff
2005-11-30 17:09 Gnomi Note Added: 0000430
2005-12-04 21:24 lars Status new => resolved
2005-12-04 21:24 lars Fixed in Version => 3.3.713
2005-12-04 21:24 lars Resolution open => fixed
2005-12-04 21:24 lars Assigned To => lars
2005-12-04 21:24 lars Note Added: 0000443
2006-02-28 20:04 lars Status resolved => closed
2010-11-16 09:42 lars Source_changeset_attached => ldmud.git master 050d0f46
2018-01-29 18:59 lars Source_changeset_attached => ldmud.git master 050d0f46
2018-01-29 21:57 lars Source_changeset_attached => ldmud.git master 050d0f46