Add support for C90 implicitly defined functions, e.g.:

int A() {
  return X();
}

llvm-svn: 39194
This commit is contained in:
Chris Lattner 2006-11-20 06:49:47 +00:00
parent 5efbb33a6b
commit ac18be9ad2
11 changed files with 153 additions and 25 deletions

View File

@ -27,4 +27,6 @@ void Sema::Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg) {
Context.PP.Diag(Loc, DiagID, Msg);
}
const LangOptions &Sema::getLangOptions() const {
return Context.PP.getLangOptions();
}

View File

@ -25,6 +25,7 @@ namespace clang {
class Preprocessor;
class Decl;
class TypeRef;
class LangOptions;
/// Sema - This implements semantic analysis and AST building for C.
class Sema : public Action {
@ -40,6 +41,8 @@ public:
: Context(ctx), LastInGroupList(prevInGroup) {
}
const LangOptions &getLangOptions() const;
void Diag(SourceLocation Loc, unsigned DiagID,
const std::string &Msg = std::string());
@ -66,6 +69,8 @@ public:
/// no declarator (e.g. "struct foo;") is parsed.
virtual DeclTy *ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS);
Decl *ImplicitlyDefineFunction(SourceLocation Loc, IdentifierInfo &II,
Scope *S);
//===--------------------------------------------------------------------===//
// Statement Parsing Callbacks: SemaStmt.cpp.
@ -113,8 +118,9 @@ public:
// Expression Parsing Callbacks: SemaExpr.cpp.
// Primary Expressions.
virtual ExprResult ParseIdentifierExpr(SourceLocation Loc,
IdentifierInfo &II);
virtual ExprResult ParseIdentifierExpr(Scope *S, SourceLocation Loc,
IdentifierInfo &II,
bool HasTrailingLParen);
virtual ExprResult ParseSimplePrimaryExpr(SourceLocation Loc,
tok::TokenKind Kind);
virtual ExprResult ParseIntegerConstant(SourceLocation Loc);

View File

@ -17,6 +17,7 @@
#include "clang/Parse/DeclSpec.h"
#include "clang/Parse/Scope.h"
#include "clang/Lex/IdentifierTable.h"
#include "clang/Basic/LangOptions.h"
using namespace llvm;
using namespace clang;
@ -104,6 +105,33 @@ Sema::ParseFunctionDefinition(Scope *S, Declarator &D, StmtTy *Body) {
return FD;
}
/// ImplicitlyDefineFunction - An undeclared identifier was used in a function
/// call, forming a call to an implicitly defined function (per C99 6.5.1p2).
Decl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, IdentifierInfo &II,
Scope *S) {
if (getLangOptions().C99) // Extension in C99.
Diag(Loc, diag::ext_implicit_function_decl, II.getName());
else // Legal in C90, but warn about it.
Diag(Loc, diag::warn_implicit_function_decl, II.getName());
// FIXME: handle stuff like:
// void foo() { extern float X(); }
// void bar() { X(); } <-- implicit decl for X in another scope.
// Set a Declarator for the implicit definition: int foo();
DeclSpec DS;
DS.TypeSpecType = DeclSpec::TST_int;
Declarator D(DS, Declarator::BlockContext);
D.AddTypeInfo(DeclaratorTypeInfo::getFunction(false, false, true, Loc));
D.SetIdentifier(&II, Loc);
Decl *Result = static_cast<Decl*>(ParseDeclarator(S, D, 0, 0));
// Visit this implicit declaration like any other top-level form.
LastInGroupList.push_back(Result);
return Result;
}
Decl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, Decl *PrevDecl) {
assert(D.getIdentifier() && "Wrong callback for declspec withotu declarator");

View File

@ -17,6 +17,7 @@
#include "clang/AST/Expr.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
@ -239,13 +240,31 @@ Sema::ParseStringExpr(const LexerToken *StringToks, unsigned NumStringToks) {
}
Sema::ExprResult Sema::ParseIdentifierExpr(SourceLocation Loc,
IdentifierInfo &II) {
/// ParseIdentifierExpr - The parser read an identifier in expression context,
/// validate it per-C99 6.5.1. HasTrailingLParen indicates whether this
/// identifier is used in an function call context.
Sema::ExprResult Sema::ParseIdentifierExpr(Scope *S, SourceLocation Loc,
IdentifierInfo &II,
bool HasTrailingLParen) {
// Could be enum-constant or decl.
Decl *D = II.getFETokenInfo<Decl>();
if (D == 0) {
Diag(Loc, diag::err_undeclared_var_use, II.getName());
return true;
// FIXME: check to see if this is a use of a builtin. By handling builtins
// here, we can avoid having to preload tons of decls for functions.
// Otherwise, this is an imlicitly declared function reference (legal in
// C90, extension in C99).
if (HasTrailingLParen &&
// Not in C++.
!getLangOptions().CPlusPlus) {
D = ImplicitlyDefineFunction(Loc, II, S);
} else {
// If this name wasn't predeclared and if this is not a function call,
// diagnose the problem.
Diag(Loc, diag::err_undeclared_var_use, II.getName());
return true;
}
}
if (isa<TypeDecl>(D)) {

View File

@ -201,8 +201,9 @@ ParseExpressionWithLeadingIdentifier(const LexerToken &Tok) {
// primary-expression: identifier
// Let the actions module handle the identifier.
ExprResult Res = Actions.ParseIdentifierExpr(Tok.getLocation(),
*Tok.getIdentifierInfo());
ExprResult Res = Actions.ParseIdentifierExpr(CurScope, Tok.getLocation(),
*Tok.getIdentifierInfo(),
Tok.getKind() == tok::l_paren);
// Because we have to parse an entire cast-expression before starting the
// ParseRHSOfBinaryExpression method (which parses any trailing binops), we
@ -231,8 +232,9 @@ ParseAssignmentExprWithLeadingIdentifier(const LexerToken &Tok) {
// primary-expression: identifier
// Let the actions module handle the identifier.
ExprResult Res = Actions.ParseIdentifierExpr(Tok.getLocation(),
*Tok.getIdentifierInfo());
ExprResult Res = Actions.ParseIdentifierExpr(CurScope, Tok.getLocation(),
*Tok.getIdentifierInfo(),
Tok.getKind() == tok::l_paren);
// Because we have to parse an entire cast-expression before starting the
// ParseRHSOfBinaryExpression method (which parses any trailing binops), we
@ -479,13 +481,19 @@ Parser::ExprResult Parser::ParseCastExpression(bool isUnaryExpression) {
// These can be followed by postfix-expr pieces.
return ParsePostfixExpressionSuffix(Res);
case tok::identifier: // primary-expression: identifier
case tok::identifier: { // primary-expression: identifier
// constant: enumeration-constant
Res = Actions.ParseIdentifierExpr(Tok.getLocation(),
*Tok.getIdentifierInfo());
ConsumeToken();
// Consume the identifier so that we can see if it is followed by a '('.
// Function designators are allowed to be undeclared (C99 6.5.1p2), so we
// need to know whether or not this identifier is a function designator or
// not.
IdentifierInfo &II = *Tok.getIdentifierInfo();
SourceLocation L = ConsumeToken();
Res = Actions.ParseIdentifierExpr(CurScope, L, II,
Tok.getKind() == tok::l_paren);
// These can be followed by postfix-expr pieces.
return ParsePostfixExpressionSuffix(Res);
}
case tok::char_constant: // constant: character-constant
case tok::kw___func__: // primary-expression: __func__ [C99 6.4.2.2]
case tok::kw___FUNCTION__: // primary-expression: __FUNCTION__ [GNU]

View File

@ -27,4 +27,6 @@ void Sema::Diag(SourceLocation Loc, unsigned DiagID, const std::string &Msg) {
Context.PP.Diag(Loc, DiagID, Msg);
}
const LangOptions &Sema::getLangOptions() const {
return Context.PP.getLangOptions();
}

View File

@ -25,6 +25,7 @@ namespace clang {
class Preprocessor;
class Decl;
class TypeRef;
class LangOptions;
/// Sema - This implements semantic analysis and AST building for C.
class Sema : public Action {
@ -40,6 +41,8 @@ public:
: Context(ctx), LastInGroupList(prevInGroup) {
}
const LangOptions &getLangOptions() const;
void Diag(SourceLocation Loc, unsigned DiagID,
const std::string &Msg = std::string());
@ -66,6 +69,8 @@ public:
/// no declarator (e.g. "struct foo;") is parsed.
virtual DeclTy *ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS);
Decl *ImplicitlyDefineFunction(SourceLocation Loc, IdentifierInfo &II,
Scope *S);
//===--------------------------------------------------------------------===//
// Statement Parsing Callbacks: SemaStmt.cpp.
@ -113,8 +118,9 @@ public:
// Expression Parsing Callbacks: SemaExpr.cpp.
// Primary Expressions.
virtual ExprResult ParseIdentifierExpr(SourceLocation Loc,
IdentifierInfo &II);
virtual ExprResult ParseIdentifierExpr(Scope *S, SourceLocation Loc,
IdentifierInfo &II,
bool HasTrailingLParen);
virtual ExprResult ParseSimplePrimaryExpr(SourceLocation Loc,
tok::TokenKind Kind);
virtual ExprResult ParseIntegerConstant(SourceLocation Loc);

View File

@ -17,6 +17,7 @@
#include "clang/Parse/DeclSpec.h"
#include "clang/Parse/Scope.h"
#include "clang/Lex/IdentifierTable.h"
#include "clang/Basic/LangOptions.h"
using namespace llvm;
using namespace clang;
@ -104,6 +105,33 @@ Sema::ParseFunctionDefinition(Scope *S, Declarator &D, StmtTy *Body) {
return FD;
}
/// ImplicitlyDefineFunction - An undeclared identifier was used in a function
/// call, forming a call to an implicitly defined function (per C99 6.5.1p2).
Decl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, IdentifierInfo &II,
Scope *S) {
if (getLangOptions().C99) // Extension in C99.
Diag(Loc, diag::ext_implicit_function_decl, II.getName());
else // Legal in C90, but warn about it.
Diag(Loc, diag::warn_implicit_function_decl, II.getName());
// FIXME: handle stuff like:
// void foo() { extern float X(); }
// void bar() { X(); } <-- implicit decl for X in another scope.
// Set a Declarator for the implicit definition: int foo();
DeclSpec DS;
DS.TypeSpecType = DeclSpec::TST_int;
Declarator D(DS, Declarator::BlockContext);
D.AddTypeInfo(DeclaratorTypeInfo::getFunction(false, false, true, Loc));
D.SetIdentifier(&II, Loc);
Decl *Result = static_cast<Decl*>(ParseDeclarator(S, D, 0, 0));
// Visit this implicit declaration like any other top-level form.
LastInGroupList.push_back(Result);
return Result;
}
Decl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, Decl *PrevDecl) {
assert(D.getIdentifier() && "Wrong callback for declspec withotu declarator");

View File

@ -17,6 +17,7 @@
#include "clang/AST/Expr.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
@ -239,13 +240,31 @@ Sema::ParseStringExpr(const LexerToken *StringToks, unsigned NumStringToks) {
}
Sema::ExprResult Sema::ParseIdentifierExpr(SourceLocation Loc,
IdentifierInfo &II) {
/// ParseIdentifierExpr - The parser read an identifier in expression context,
/// validate it per-C99 6.5.1. HasTrailingLParen indicates whether this
/// identifier is used in an function call context.
Sema::ExprResult Sema::ParseIdentifierExpr(Scope *S, SourceLocation Loc,
IdentifierInfo &II,
bool HasTrailingLParen) {
// Could be enum-constant or decl.
Decl *D = II.getFETokenInfo<Decl>();
if (D == 0) {
Diag(Loc, diag::err_undeclared_var_use, II.getName());
return true;
// FIXME: check to see if this is a use of a builtin. By handling builtins
// here, we can avoid having to preload tons of decls for functions.
// Otherwise, this is an imlicitly declared function reference (legal in
// C90, extension in C99).
if (HasTrailingLParen &&
// Not in C++.
!getLangOptions().CPlusPlus) {
D = ImplicitlyDefineFunction(Loc, II, S);
} else {
// If this name wasn't predeclared and if this is not a function call,
// diagnose the problem.
Diag(Loc, diag::err_undeclared_var_use, II.getName());
return true;
}
}
if (isa<TypeDecl>(D)) {

View File

@ -392,7 +392,12 @@ DIAG(err_unspecified_vla_size_with_static, ERROR,
DIAG(err_unexpected_typedef, ERROR,
"unexpected type name '%s': expected expression")
DIAG(err_undeclared_var_use, ERROR,
"use of undeclared '%s' value")
"use of undeclared identifier '%s'")
DIAG(warn_implicit_function_decl, WARNING,
"implicit declaration of function '%s'")
DIAG(ext_implicit_function_decl, EXTENSION,
"implicit declaration of function '%s' is invalid in C99")
DIAG(err_continue_not_in_loop, ERROR,
"'continue' statement not in loop statement")

View File

@ -211,8 +211,13 @@ public:
//===--------------------------------------------------------------------===//
// Primary Expressions.
virtual ExprResult ParseIdentifierExpr(SourceLocation Loc,
IdentifierInfo &II) {
/// ParseIdentifierExpr - Parse an identifier in expression context.
/// 'HasTrailingLParen' indicates whether or not the identifier has a '('
/// token immediately after it.
virtual ExprResult ParseIdentifierExpr(Scope *S, SourceLocation Loc,
IdentifierInfo &II,
bool HasTrailingLParen) {
return 0;
}