Add support for C90 implicitly defined functions, e.g.:
int A() { return X(); } llvm-svn: 39194
This commit is contained in:
parent
5efbb33a6b
commit
ac18be9ad2
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue