diff --git a/clang/AST/Sema.cpp b/clang/AST/Sema.cpp index a3d2185abde1..78a058b71f05 100644 --- a/clang/AST/Sema.cpp +++ b/clang/AST/Sema.cpp @@ -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(); +} diff --git a/clang/AST/Sema.h b/clang/AST/Sema.h index 8a5f512fcb45..f6c965c6372b 100644 --- a/clang/AST/Sema.h +++ b/clang/AST/Sema.h @@ -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); diff --git a/clang/AST/SemaDecl.cpp b/clang/AST/SemaDecl.cpp index a90831df9ba9..8e57fa787340 100644 --- a/clang/AST/SemaDecl.cpp +++ b/clang/AST/SemaDecl.cpp @@ -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(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"); diff --git a/clang/AST/SemaExpr.cpp b/clang/AST/SemaExpr.cpp index ac3a954bf705..1e9e35397172 100644 --- a/clang/AST/SemaExpr.cpp +++ b/clang/AST/SemaExpr.cpp @@ -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(); 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(D)) { diff --git a/clang/Parse/ParseExpr.cpp b/clang/Parse/ParseExpr.cpp index 645ab3307b04..b2fa6737a7e2 100644 --- a/clang/Parse/ParseExpr.cpp +++ b/clang/Parse/ParseExpr.cpp @@ -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] diff --git a/clang/Sema/Sema.cpp b/clang/Sema/Sema.cpp index a3d2185abde1..78a058b71f05 100644 --- a/clang/Sema/Sema.cpp +++ b/clang/Sema/Sema.cpp @@ -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(); +} diff --git a/clang/Sema/Sema.h b/clang/Sema/Sema.h index 8a5f512fcb45..f6c965c6372b 100644 --- a/clang/Sema/Sema.h +++ b/clang/Sema/Sema.h @@ -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); diff --git a/clang/Sema/SemaDecl.cpp b/clang/Sema/SemaDecl.cpp index a90831df9ba9..8e57fa787340 100644 --- a/clang/Sema/SemaDecl.cpp +++ b/clang/Sema/SemaDecl.cpp @@ -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(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"); diff --git a/clang/Sema/SemaExpr.cpp b/clang/Sema/SemaExpr.cpp index ac3a954bf705..1e9e35397172 100644 --- a/clang/Sema/SemaExpr.cpp +++ b/clang/Sema/SemaExpr.cpp @@ -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(); 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(D)) { diff --git a/clang/include/clang/Basic/DiagnosticKinds.def b/clang/include/clang/Basic/DiagnosticKinds.def index ee24458c91b7..1e44c90dd5ec 100644 --- a/clang/include/clang/Basic/DiagnosticKinds.def +++ b/clang/include/clang/Basic/DiagnosticKinds.def @@ -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") diff --git a/clang/include/clang/Parse/Action.h b/clang/include/clang/Parse/Action.h index 9e30a7484200..34af457f510c 100644 --- a/clang/include/clang/Parse/Action.h +++ b/clang/include/clang/Parse/Action.h @@ -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; }