Fungus
Fungus

Reputation: 41

Cannot see cause for "control reaches end of non-void function [-Wreturn-type]"

I'm now pretty certain my IDE is screwing up, it isn't reporting the warning consistently, so I think there may not be a problem with the first block of code after all. I'm not sure however; I use Eclipse Juno for C/C++ Developers with a Mingw setup if that helps.

I've been learning C++ from Stroustrup's excellent book Programming - Principles and Practice Using C++. I've managed to solve most of my problems through this site and others without asking, but this one evades me: Why am I receiving the warning "control reaches end of non-void function [-Wreturn-type]" for this code?

Token get_token(){    // read a token from cin
    char ch;
    cin >> ch;    // note that >> skips whitespace (space, newline, tab, etc.)
    switch (ch) {
 //not yet   case ';':    // for "print"
 //not yet   case 'q':    // for "quit"
    case '(': case ')': case '+': case '-': case '*': case '/': 
        return Token(ch);        // let each character represent itself
    case '.':
    case '0': case '1': case '2': case '3': case '4':
    case '5': case '6': case '7': case '8': case '9':
    {
         cin.putback(ch);         // put digit back into the input stream
         double val;
         cin >> val;              // read a floating-point number
         return Token('8',val);   // let '8' represent "a number"
    }
    default:
        {error("Bad token");
        return 1;}
    }
}

There are two of these warnings and three "No return, in function returning non-void". What's going on? An example of the latter:

double term(){
    double left = primary();
    Token t = get_token();     // get the next token
    while(true) {
        switch (t.kind) {
             case '*':
                 left *= primary();
                 t = get_token();
                 break;
             case '/':
             {    
                  double d = primary();
                  if (d == 0) error("divide by zero");
                     left /= d; 
                  t = get_token();
                  break;
             }
             default: 
                 return left;
        }
    }
}

The entire code can be downloaded here.

Upvotes: 4

Views: 1367

Answers (2)

eric
eric

Reputation: 8078

This is a simple fix: the problem is your function has a case where no return statement is provided. As they say about this warning at the IBM knowledge center, the most direct way to deal with this is to add a return statement:

At the end of the function, add a return statement that returns a suitable return value, even if control never reaches there.

As mentioned in the comments, you haven't actually pasted Stroustrup's code, but a modified version. In his original code, the problem is there was no return for the default line, so you should provide one.

Here is my modified version that compiles without warning. Note I return an arbitrary instance of type Token, which will never be reached because the code throws an error first anyway:

//Prompt user for a token
Token get_token()    // read a token from cin
{
  char ch;
  cout << "\nIn get_token: enter a token: ";
  cin >> ch;    // note that >> skips whitespace (space, newline, tab, etc.)

  switch (ch)
  {
    //character tokens
    case '(':
    case ')':
    case '+':
    case '-':
    case '*':
    case '/':
      return Token(ch);    // let each character represent itself
    //numerical tokens
    case '.':
    case '0':
    case '1':
    case '2':
    case '3':
    case '4':
    case '5':
    case '6':
    case '7':
    case '8':
    case '9':
      {
          cin.putback(ch);   // put digit back into the input stream to recast as double
          double val;
          cin >> val;       // read as a floating-point number
          //initialize number token
          return Token('8',val);   // let '8' represent "a number"
      }
  default:
      error("CUSTOM ERROR: Bad token: must be number, mathematical operator, or paren.");
      return Token('x');  //otherwise get 'control reaches end of non-void function' warning
  }  //switch
}

Upvotes: 0

user3392484
user3392484

Reputation: 1919

Logically, the end of each function can't be reached, because in the first case you switch() with a default, returning in each branch, and in the second there's an infinite loop without any break statement out of it. However, you're relying on the compiler to figure that out (e.g. via flow analysis). If it can't then it'll complain that you can reach the end of the function without returning.

I've seen this with HP's compiler, which doesn't seem to do much flow analysis. gcc 4.8 doesn't complain about your this. However, if you want to be (a) portable and (b) warning-free, then just adding a return statement may cause "Unreachable code" warnings in the compiler(s) that are currently silent. Within my company we get round that by saying RETURN_IF_NO_FLOW_ANALYSIS (0), where RETURN_IF_NO_FLOW_ANALYSIS(x) is a macro that evaluates to nothing on MSVC, gcc etc., and "return x;" on e.g. HP's compiler. That keeps us warning free - we compile with warnings-as-errors. Not particularly pretty though: if anyone knows a better way around that then I'm interested...

Upvotes: 1

Related Questions