From 04421087832a031c90bd58f128c7c0e741db8dd2 Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Tue, 8 Apr 2008 04:40:51 +0000 Subject: [PATCH] Add support for C++ default arguments, and rework Parse-Sema interaction for function parameters, fixing PR2046. Patch by Doug Gregor! git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@49369 91177308-0d34-0410-b5e6-96231b3b80d8 --- Driver/clang.cpp | 9 + include/clang/AST/Decl.h | 15 +- include/clang/AST/ExprCXX.h | 39 +++++ include/clang/AST/StmtNodes.def | 1 + include/clang/Basic/DiagnosticKinds.def | 12 +- include/clang/Parse/Action.h | 19 +- include/clang/Parse/DeclSpec.h | 10 +- lib/AST/Decl.cpp | 4 +- lib/AST/DeclSerialization.cpp | 5 +- lib/AST/Expr.cpp | 15 ++ lib/AST/ExprCXX.cpp | 8 + lib/AST/StmtPrinter.cpp | 9 + lib/AST/StmtSerialization.cpp | 21 +++ lib/CodeGen/CGExprAgg.cpp | 3 + lib/CodeGen/CGExprComplex.cpp | 3 + lib/CodeGen/CGExprConstant.cpp | 4 + lib/CodeGen/CGExprScalar.cpp | 5 +- lib/Parse/ParseDecl.cpp | 52 ++++-- lib/Parse/Parser.cpp | 17 +- lib/Sema/Sema.h | 15 +- lib/Sema/SemaDecl.cpp | 224 +++++++++++++++++------- lib/Sema/SemaDeclObjC.cpp | 31 ++-- lib/Sema/SemaExpr.cpp | 53 ++++-- lib/Sema/SemaType.cpp | 39 +---- test/CodeGen/cxx-default-arg.cpp | 25 +++ test/Sema/arg-scope-c99.c | 2 + test/Sema/arg-scope.c | 5 + test/Sema/default1.c | 2 + test/Sema/default1.cpp | 17 ++ test/Sema/default2.cpp | 12 ++ 30 files changed, 498 insertions(+), 178 deletions(-) create mode 100644 test/CodeGen/cxx-default-arg.cpp create mode 100644 test/Sema/arg-scope-c99.c create mode 100644 test/Sema/arg-scope.c create mode 100644 test/Sema/default1.c create mode 100644 test/Sema/default1.cpp create mode 100644 test/Sema/default2.cpp diff --git a/Driver/clang.cpp b/Driver/clang.cpp index 397c27db54..6c82f19572 100644 --- a/Driver/clang.cpp +++ b/Driver/clang.cpp @@ -901,6 +901,11 @@ static void InitializeIncludePaths(const char *Argv0, HeaderSearch &Headers, false, Headers); AddPath("/usr/include/c++/4.1.3/backward", System, true, false, false, Headers); + + // Fedora 8 + AddPath("/usr/include/c++/4.1.2", System, true, false, false, Headers); + AddPath("/usr/include/c++/4.1.2/i386-redhat-linux", System, true, false, false, Headers); + AddPath("/usr/include/c++/4.1.2/backward", System, true, false, false, Headers); } AddPath("/usr/local/include", System, false, false, false, Headers); @@ -926,6 +931,10 @@ static void InitializeIncludePaths(const char *Argv0, HeaderSearch &Headers, AddPath("/usr/lib/gcc/i486-linux-gnu/4.1.3/include", System, false, false, false, Headers); + // Fedora 8 + AddPath("/usr/lib/gcc/i386-redhat-linux/4.1.2/include", System, + false, false, false, Headers); + //Debian testing/lenny x86 AddPath("/usr/lib/gcc/i486-linux-gnu/4.2.3/include", System, false, false, false, Headers); diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 3bae5e2d4c..bce65f9b57 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -246,15 +246,20 @@ class ParmVarDecl : public VarDecl { /// in, inout, etc. unsigned objcDeclQualifier : 6; + /// Default argument, if any. [C++ Only] + Expr *DefaultArg; + ParmVarDecl(DeclContext *CD, SourceLocation L, IdentifierInfo *Id, QualType T, StorageClass S, - ScopedDecl *PrevDecl) + Expr *DefArg, ScopedDecl *PrevDecl) : VarDecl(ParmVar, CD, L, Id, T, S, PrevDecl), - objcDeclQualifier(OBJC_TQ_None) {} + objcDeclQualifier(OBJC_TQ_None), DefaultArg(DefArg) {} + public: static ParmVarDecl *Create(ASTContext &C, DeclContext *CD, SourceLocation L,IdentifierInfo *Id, - QualType T, StorageClass S, ScopedDecl *PrevDecl); + QualType T, StorageClass S, Expr *DefArg, + ScopedDecl *PrevDecl); ObjCDeclQualifier getObjCDeclQualifier() const { return ObjCDeclQualifier(objcDeclQualifier); @@ -262,6 +267,10 @@ public: void setObjCDeclQualifier(ObjCDeclQualifier QTVal) { objcDeclQualifier = QTVal; } + const Expr *getDefaultArg() const { return DefaultArg; } + Expr *getDefaultArg() { return DefaultArg; } + void setDefaultArg(Expr *defarg) { DefaultArg = defarg; } + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return D->getKind() == ParmVar; } static bool classof(const ParmVarDecl *D) { return true; } diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index 357fb9538f..3c99321a8a 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -127,6 +127,45 @@ namespace clang { virtual child_iterator child_end(); }; + /// CXXDefaultArgExpr - C++ [dcl.fct.default]. This wraps up a + /// function call argument that was created from the corresponding + /// parameter's default argument, when the call did not explicitly + /// supply arguments for all of the parameters. + class CXXDefaultArgExpr : public Expr { + ParmVarDecl *Param; + public: + // Param is the parameter whose default argument is used by this + // expression. + explicit CXXDefaultArgExpr(ParmVarDecl *param) + : Expr(CXXDefaultArgExprClass, param->getDefaultArg()->getType()), + Param(param) { } + + // Retrieve the parameter that the argument was created from. + const ParmVarDecl *getParam() const { return Param; } + ParmVarDecl *getParam() { return Param; } + + // Retrieve the actual argument to the function call. + const Expr *getExpr() const { return Param->getDefaultArg(); } + Expr *getExpr() { return Param->getDefaultArg(); } + + virtual SourceRange getSourceRange() const { + return Param->getDefaultArg()->getSourceRange(); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXDefaultArgExprClass; + } + static bool classof(const CXXDefaultArgExpr *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); + + // Serialization + virtual void EmitImpl(llvm::Serializer& S) const; + static CXXDefaultArgExpr* CreateImpl(llvm::Deserializer& D, + ASTContext& C); + }; } // end namespace clang #endif diff --git a/include/clang/AST/StmtNodes.def b/include/clang/AST/StmtNodes.def index 4c0fd7a242..e3f0273308 100644 --- a/include/clang/AST/StmtNodes.def +++ b/include/clang/AST/StmtNodes.def @@ -91,6 +91,7 @@ STMT(58, ChooseExpr , Expr) STMT(60, CXXCastExpr , Expr) STMT(61, CXXBoolLiteralExpr , Expr) STMT(62, CXXThrowExpr , Expr) +STMT(63, CXXDefaultArgExpr , Expr) // Obj-C Expressions. STMT(70, ObjCStringLiteral , Expr) diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index 1de1b6b80f..611edf51f5 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -243,7 +243,6 @@ DIAG(err_pp_I_dash_not_supported, ERROR, //===----------------------------------------------------------------------===// // Parser Diagnostics //===----------------------------------------------------------------------===// - DIAG(w_type_defaults_to_int, WARNING, "type defaults to 'int'") DIAG(w_no_declarators, WARNING, @@ -314,7 +313,7 @@ DIAG(ext_gnu_old_style_field_designator, EXTENSION, "use of GNU old-style field designator extension") DIAG(ext_gnu_case_range, EXTENSION, "use of GNU case range extension") - + // Generic errors. DIAG(err_parse_error, ERROR, "parse error") @@ -621,7 +620,14 @@ DIAG(err_no_matching_param, ERROR, "parameter named '%0' is missing") DIAG(ext_param_not_declared, EXTENSION, "parameter '%0' was not declared, defaulting to type 'int'") - +DIAG(err_param_default_argument, ERROR, + "C does not support default arguments") +DIAG(err_param_default_argument_redefinition, ERROR, + "redefinition of default argument") +DIAG(err_param_default_argument_missing, ERROR, + "missing default argument on parameter") +DIAG(err_param_default_argument_missing_name, ERROR, + "missing default argument on parameter '%0'") DIAG(err_previous_definition, ERROR, "previous definition is here") DIAG(err_previous_use, ERROR, diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index 83d1fea715..fb180c2d1a 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -107,6 +107,14 @@ public: return 0; } + /// ActOnParamDeclarator - This callback is invoked when a parameter + /// declarator is parsed. This callback only occurs for functions + /// with prototypes. S is the function prototype scope for the + /// parameters (C++ [basic.scope.proto]). + virtual DeclTy *ActOnParamDeclarator(Scope *S, Declarator &D) { + return 0; + } + /// AddInitializerToDecl - This action is called immediately after /// ParseDeclarator (when an initializer is present). The code is factored /// this way to make sure we are able to handle the following: @@ -173,10 +181,6 @@ public: return 0; } - virtual TypeResult ActOnParamDeclaratorType(Scope *S, Declarator &D) { - return 0; - } - enum TagKind { TK_Reference, // Reference to a tag: 'struct foo *X;' TK_Declaration, // Fwd decl of a tag: 'struct foo;' @@ -503,6 +507,13 @@ public: SourceLocation RPLoc) { return 0; } + + //===------------------------- C++ Declarations -------------------------===// + /// ActOnParamDefaultArgument - Parse default argument for function parameter + virtual void ActOnParamDefaultArgument(DeclTy *param, + SourceLocation EqualLoc, + ExprTy *defarg) { + } //===------------------------- C++ Expressions --------------------------===// diff --git a/include/clang/Parse/DeclSpec.h b/include/clang/Parse/DeclSpec.h index e52f307e6e..6204a383b9 100644 --- a/include/clang/Parse/DeclSpec.h +++ b/include/clang/Parse/DeclSpec.h @@ -416,14 +416,10 @@ struct DeclaratorChunk { struct ParamInfo { IdentifierInfo *Ident; SourceLocation IdentLoc; - Action::TypeTy *TypeInfo; - bool InvalidType; - AttributeList *AttrList; + Action::DeclTy *Param; ParamInfo() {} - ParamInfo(IdentifierInfo *ident, SourceLocation iloc, Action::TypeTy *typ, - bool flag = false, AttributeList *AL = 0) - : Ident(ident), IdentLoc(iloc), TypeInfo(typ), InvalidType(flag), - AttrList(AL) {} + ParamInfo(IdentifierInfo *ident, SourceLocation iloc, Action::DeclTy *param) + : Ident(ident), IdentLoc(iloc), Param(param) {} }; struct FunctionTypeInfo { diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index e27015b7ef..8228eceebf 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -224,9 +224,9 @@ FileVarDecl *FileVarDecl::Create(ASTContext &C, DeclContext *CD, ParmVarDecl *ParmVarDecl::Create(ASTContext &C, DeclContext *CD, SourceLocation L, IdentifierInfo *Id, QualType T, StorageClass S, - ScopedDecl *PrevDecl) { + Expr *DefArg, ScopedDecl *PrevDecl) { void *Mem = C.getAllocator().Allocate(); - return new (Mem) ParmVarDecl(CD, L, Id, T, S, PrevDecl); + return new (Mem) ParmVarDecl(CD, L, Id, T, S, DefArg, PrevDecl); } FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *CD, diff --git a/lib/AST/DeclSerialization.cpp b/lib/AST/DeclSerialization.cpp index bc5310c414..14666d6f00 100644 --- a/lib/AST/DeclSerialization.cpp +++ b/lib/AST/DeclSerialization.cpp @@ -226,15 +226,16 @@ FileVarDecl* FileVarDecl::CreateImpl(Deserializer& D, ASTContext& C) { void ParmVarDecl::EmitImpl(llvm::Serializer& S) const { VarDecl::EmitImpl(S); S.EmitInt(getObjCDeclQualifier()); // From ParmVarDecl. + S.EmitOwnedPtr(getDefaultArg()); // From ParmVarDecl. } ParmVarDecl* ParmVarDecl::CreateImpl(Deserializer& D, ASTContext& C) { ParmVarDecl* decl = - new ParmVarDecl(0, SourceLocation(),NULL,QualType(),None,NULL); + new ParmVarDecl(0, SourceLocation(), NULL, QualType(), None, NULL, NULL); decl->VarDecl::ReadImpl(D, C); decl->objcDeclQualifier = static_cast(D.ReadInt()); - + decl->DefaultArg = D.ReadOwnedPtr(C); return decl; } diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 5205702f29..0287aa0831 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -337,6 +337,9 @@ bool Expr::hasLocalSideEffect() const { if (getType()->isVoidType()) return cast(this)->getSubExpr()->hasLocalSideEffect(); return false; + + case CXXDefaultArgExprClass: + return cast(this)->getExpr()->hasLocalSideEffect(); } } @@ -401,6 +404,8 @@ Expr::isLvalueResult Expr::isLvalue() const { return LV_Valid; case PreDefinedExprClass: return LV_Valid; + case CXXDefaultArgExprClass: + return cast(this)->getExpr()->isLvalue(); default: break; } @@ -465,6 +470,8 @@ bool Expr::hasGlobalStorage() const { return cast(this)->getBase()->hasGlobalStorage(); case PreDefinedExprClass: return true; + case CXXDefaultArgExprClass: + return cast(this)->getExpr()->hasGlobalStorage(); } } @@ -636,6 +643,8 @@ bool Expr::isConstantExpr(ASTContext &Ctx, SourceLocation *Loc) const { } return true; } + case CXXDefaultArgExprClass: + return cast(this)->getExpr()->isConstantExpr(Ctx, Loc); } } @@ -981,6 +990,9 @@ bool Expr::isIntegerConstantExpr(llvm::APSInt &Result, ASTContext &Ctx, return false; break; } + case CXXDefaultArgExprClass: + return cast(this) + ->isIntegerConstantExpr(Result, Ctx, Loc, isEvaluated); } // Cases that are valid constant exprs fall through to here. @@ -1009,6 +1021,9 @@ bool Expr::isNullPointerConstant(ASTContext &Ctx) const { // Accept ((void*)0) as a null pointer constant, as many other // implementations do. return PE->getSubExpr()->isNullPointerConstant(Ctx); + } else if (const CXXDefaultArgExpr *DefaultArg = dyn_cast(this)) { + // See through default argument expressions + return DefaultArg->getExpr()->isNullPointerConstant(Ctx); } // This expression must be an integer type. diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index 3bc32e75d8..03faf8b8b5 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -45,3 +45,11 @@ Stmt::child_iterator CXXThrowExpr::child_end() { return reinterpret_cast(&Op)+0; return reinterpret_cast(&Op)+1; } + +// CXXDefaultArgExpr +Stmt::child_iterator CXXDefaultArgExpr::child_begin() { + return reinterpret_cast(Param->getDefaultArg()); +} +Stmt::child_iterator CXXDefaultArgExpr::child_end() { + return reinterpret_cast(Param->getDefaultArg())+1; +} diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index ba82b7fcff..a76fd1f9b5 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -658,6 +658,11 @@ void StmtPrinter::VisitCallExpr(CallExpr *Call) { PrintExpr(Call->getCallee()); OS << "("; for (unsigned i = 0, e = Call->getNumArgs(); i != e; ++i) { + if (isa(Call->getArg(i))) { + // Don't print any defaulted arguments + break; + } + if (i) OS << ", "; PrintExpr(Call->getArg(i)); } @@ -789,6 +794,10 @@ void StmtPrinter::VisitCXXThrowExpr(CXXThrowExpr *Node) { } } +void StmtPrinter::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *Node) { + // Nothing to print: we picked up the default argument +} + // Obj-C void StmtPrinter::VisitObjCStringLiteral(ObjCStringLiteral *Node) { diff --git a/lib/AST/StmtSerialization.cpp b/lib/AST/StmtSerialization.cpp index 41569df8f2..7058c0ce2f 100644 --- a/lib/AST/StmtSerialization.cpp +++ b/lib/AST/StmtSerialization.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" #include "llvm/Bitcode/Serialize.h" #include "llvm/Bitcode/Deserialize.h" @@ -185,6 +186,13 @@ Stmt* Stmt::Create(Deserializer& D, ASTContext& C) { case ObjCStringLiteralClass: return ObjCStringLiteral::CreateImpl(D, C); + + //==--------------------------------------==// + // C++ + //==--------------------------------------==// + case CXXDefaultArgExprClass: + return CXXDefaultArgExpr::CreateImpl(D, C); + } } @@ -1002,3 +1010,16 @@ ObjCStringLiteral* ObjCStringLiteral::CreateImpl(Deserializer& D, ASTContext& C) StringLiteral* String = cast(D.ReadOwnedPtr(C)); return new ObjCStringLiteral(String,T,L); } + +//===----------------------------------------------------------------------===// +// C++ Serialization +//===----------------------------------------------------------------------===// +void CXXDefaultArgExpr::EmitImpl(Serializer& S) const { + S.EmitPtr(Param); +} + +CXXDefaultArgExpr *CXXDefaultArgExpr::CreateImpl(Deserializer& D, ASTContext& C) { + ParmVarDecl* Param = 0; + D.ReadPtr(Param, false); + return new CXXDefaultArgExpr(Param); +} diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index 3bfcc10f7f..b5c755a582 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -86,6 +86,9 @@ public: void VisitConditionalOperator(const ConditionalOperator *CO); void VisitInitListExpr(InitListExpr *E); + void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) { + Visit(DAE->getExpr()); + } void EmitInitializationToLValue(Expr *E, LValue Address); void EmitNullInitializationToLValue(LValue Address, QualType T); diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp index 1e8c8a37f2..a486d6ae15 100644 --- a/lib/CodeGen/CGExprComplex.cpp +++ b/lib/CodeGen/CGExprComplex.cpp @@ -120,6 +120,9 @@ public: ComplexPairTy VisitUnaryExtension(const UnaryOperator *E) { return Visit(E->getSubExpr()); } + ComplexPairTy VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) { + return Visit(DAE->getExpr()); + } struct BinOpInfo { ComplexPairTy LHS; diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index e2405b88f3..2ca71c3153 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -69,6 +69,10 @@ public: return EmitConversion(C, E->getSubExpr()->getType(), E->getType()); } + llvm::Constant *VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) { + return Visit(DAE->getExpr()); + } + llvm::Constant *EmitArrayInitialization(InitListExpr *ILE, const llvm::ArrayType *AType) { std::vector Elts; diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index 89779075a4..2f03f88ebf 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -169,7 +169,7 @@ public: Value *VisitCompoundLiteralExpr(CompoundLiteralExpr *E) { return Visit(E->getInitializer()); } - + Value *VisitImplicitCastExpr(const ImplicitCastExpr *E); Value *VisitCastExpr(const CastExpr *E) { return EmitCastExpr(E->getSubExpr(), E->getType()); @@ -220,6 +220,9 @@ public: return Visit(E->getSubExpr()); } Value *VisitUnaryOffsetOf(const UnaryOperator *E); + Value *VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) { + return Visit(DAE->getExpr()); + } // Binary Operators. Value *EmitMul(const BinOpInfo &Ops) { diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 0eb5c1f257..0eb95fa908 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -1232,8 +1232,10 @@ void Parser::ParseParenDeclarator(Declarator &D) { /// /// parameter-declaration: [C99 6.7.5] /// declaration-specifiers declarator +/// [C++] declaration-specifiers declarator '=' assignment-expression /// [GNU] declaration-specifiers declarator attributes /// declaration-specifiers abstract-declarator[opt] +/// [C++] declaration-specifiers abstract-declarator[opt] '=' assignment-expression /// [GNU] declaration-specifiers abstract-declarator[opt] attributes /// void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D) { @@ -1265,11 +1267,9 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D) { // Build up an array of information about the parsed arguments. llvm::SmallVector ParamInfo; - llvm::SmallSet ParamsSoFar; - - // Enter function-declaration scope, limiting any declarators for struct - // tags to the function prototype scope. - // FIXME: is this needed? + + // Enter function-declaration scope, limiting any declarators to the + // function prototype scope, including parameter declarators. EnterScope(Scope::DeclScope); bool IsVariadic = false; @@ -1307,14 +1307,6 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D) { // Remember this parsed parameter in ParamInfo. IdentifierInfo *ParmII = ParmDecl.getIdentifier(); - // Verify that the argument identifier has not already been mentioned. - if (ParmII && !ParamsSoFar.insert(ParmII)) { - Diag(ParmDecl.getIdentifierLoc(), diag::err_param_redefinition, - ParmII->getName()); - ParmII = 0; - ParmDecl.setInvalidType(true); - } - // If no parameter was specified, verify that *something* was specified, // otherwise we have a missing type and identifier. if (DS.getParsedSpecifiers() == DeclSpec::PQ_None && @@ -1327,12 +1319,37 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D) { // Inform the actions module about the parameter declarator, so it gets // added to the current scope. - Action::TypeResult ParamTy = - Actions.ActOnParamDeclaratorType(CurScope, ParmDecl); + DeclTy *Param = Actions.ActOnParamDeclarator(CurScope, ParmDecl); + + // Parse the default argument, if any. We parse the default + // arguments in all dialects; the semantic analysis in + // ActOnParamDefaultArgument will reject the default argument in + // C. + if (Tok.is(tok::equal)) { + SourceLocation EqualLoc = Tok.getLocation(); + + // Consume the '='. + ConsumeToken(); + + // Parse the default argument + // FIXME: For C++, name lookup from within the default argument + // should be able to find parameter names, but we haven't put them + // in the scope. This means that we will accept ill-formed code + // such as: + // + // int x; + // void f(int x = x) { } + ExprResult DefArgResult = ParseAssignmentExpression(); + if (DefArgResult.isInvalid) { + SkipUntil(tok::comma, tok::r_paren, true, true); + } else { + // Inform the actions module about the default argument + Actions.ActOnParamDefaultArgument(Param, EqualLoc, DefArgResult.Val); + } + } ParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII, - ParmDecl.getIdentifierLoc(), ParamTy.Val, ParmDecl.getInvalidType(), - ParmDecl.getDeclSpec().TakeAttributes())); + ParmDecl.getIdentifierLoc(), Param)); } // If the next token is a comma, consume it and keep reading arguments. @@ -1354,7 +1371,6 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D) { MatchRHSPunctuation(tok::r_paren, LParenLoc); } - /// ParseFunctionDeclaratorIdentifierList - While parsing a function declarator /// we found a K&R-style identifier list instead of a type argument list. The /// current token is known to be the first identifier in the list. diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index cd99fc04eb..7e41bcc92e 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -509,6 +509,10 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) { // We know that the top-level of this declarator is a function. DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun; + // Enter function-declaration scope, limiting any declarators to the + // function prototype scope, including parameter declarators. + EnterScope(Scope::DeclScope); + // Read all the argument declarations. while (isDeclarationSpecifier()) { SourceLocation DSStart = Tok.getLocation(); @@ -555,10 +559,10 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) { AttrList = ParseAttributes(); // Ask the actions module to compute the type for this declarator. - Action::TypeResult TR = - Actions.ActOnParamDeclaratorType(CurScope, ParmDeclarator); + Action::DeclTy *Param = + Actions.ActOnParamDeclarator(CurScope, ParmDeclarator); - if (!TR.isInvalid && + if (Param && // A missing identifier has already been diagnosed. ParmDeclarator.getIdentifier()) { @@ -575,12 +579,12 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) { if (FTI.ArgInfo[i].Ident == ParmDeclarator.getIdentifier()) { // Reject redefinitions of parameters. - if (FTI.ArgInfo[i].TypeInfo) { + if (FTI.ArgInfo[i].Param) { Diag(ParmDeclarator.getIdentifierLoc(), diag::err_param_redefinition, ParmDeclarator.getIdentifier()->getName()); } else { - FTI.ArgInfo[i].TypeInfo = TR.Val; + FTI.ArgInfo[i].Param = Param; } break; } @@ -611,6 +615,9 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) { } } + // Leave prototype scope. + ExitScope(); + // The actions module must verify that all arguments were declared. } diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 70aaf24791..b2a88eb635 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -202,14 +202,16 @@ public: virtual TypeResult ActOnTypeName(Scope *S, Declarator &D); - - virtual TypeResult ActOnParamDeclaratorType(Scope *S, Declarator &D); private: //===--------------------------------------------------------------------===// // Symbol table / Decl tracking callbacks: SemaDecl.cpp. // virtual DeclTy *isTypeName(const IdentifierInfo &II, Scope *S); virtual DeclTy *ActOnDeclarator(Scope *S, Declarator &D, DeclTy *LastInGroup); + virtual DeclTy *ActOnParamDeclarator(Scope *S, Declarator &D); + virtual void ActOnParamDefaultArgument(DeclTy *param, + SourceLocation EqualLoc, + ExprTy *defarg); void AddInitializerToDecl(DeclTy *dcl, ExprTy *init); virtual DeclTy *FinalizeDeclaratorGroup(Scope *S, DeclTy *Group); @@ -259,10 +261,15 @@ private: TypedefDecl *MergeTypeDefDecl(TypedefDecl *New, Decl *Old); FunctionDecl *MergeFunctionDecl(FunctionDecl *New, Decl *Old); VarDecl *MergeVarDecl(VarDecl *New, Decl *Old); + FunctionDecl *MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old); + + /// Helpers for dealing with function parameters + bool CheckParmsForFunctionDef(FunctionDecl *FD); + ParmVarDecl *CreateImplicitParameter(Scope *S, IdentifierInfo *Id, + SourceLocation IdLoc, QualType Type); + void CheckCXXDefaultArguments(FunctionDecl *FD); /// More parsing and symbol table subroutines... - ParmVarDecl *ActOnParamDeclarator(struct DeclaratorChunk::ParamInfo &PI, - Scope *FnBodyScope); Decl *LookupDecl(const IdentifierInfo *II, unsigned NSI, Scope *S, bool enableLazyBuiltinCreation = true); ObjCInterfaceDecl *getObjCInterfaceDecl(IdentifierInfo *Id); diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 0f464a0bc7..5451ec27c0 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -263,9 +263,10 @@ static void MergeAttributes(Decl *New, Decl *Old) { } } -/// MergeFunctionDecl - We just parsed a function 'New' which has the same name -/// and scope as a previous declaration 'Old'. Figure out how to resolve this -/// situation, merging decls or emitting diagnostics as appropriate. +/// MergeFunctionDecl - We just parsed a function 'New' from +/// declarator D which has the same name and scope as a previous +/// declaration 'Old'. Figure out how to resolve this situation, +/// merging decls or emitting diagnostics as appropriate. /// FunctionDecl *Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { // Verify the old decl was also a function. @@ -276,17 +277,24 @@ FunctionDecl *Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { Diag(OldD->getLocation(), diag::err_previous_definition); return New; } - + MergeAttributes(New, Old); - QualType OldQType = Context.getCanonicalType(Old->getType()); QualType NewQType = Context.getCanonicalType(New->getType()); - // Function types need to be compatible, not identical. This handles + // C++ [dcl.fct]p3: + // All declarations for a function shall agree exactly in both the + // return type and the parameter-type-list. + if (getLangOptions().CPlusPlus && OldQType == NewQType) + return MergeCXXFunctionDecl(New, Old); + + // C: Function types need to be compatible, not identical. This handles // duplicate function decls like "void f(int); void f(enum X);" properly. - if (Context.functionTypesAreCompatible(OldQType, NewQType)) + if (!getLangOptions().CPlusPlus && + Context.functionTypesAreCompatible(OldQType, NewQType)) { return New; + } // A function that has already been declared has been redeclared or defined // with a different type- show appropriate diagnostic @@ -295,7 +303,7 @@ FunctionDecl *Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { PrevDiag = diag::err_previous_definition; else if (Old->isImplicit()) PrevDiag = diag::err_previous_implicit_declaration; - else + else PrevDiag = diag::err_previous_declaration; // TODO: CHECK FOR CONFLICTS, multiple decls with same name in one scope. @@ -413,6 +421,49 @@ VarDecl *Sema::MergeVarDecl(VarDecl *New, Decl *OldD) { return New; } +/// CheckParmsForFunctionDef - Check that the parameters of the given +/// function are appropriate for the definition of a function. This +/// takes care of any checks that cannot be performed on the +/// declaration itself, e.g., that the types of each of the function +/// parameters are complete. +bool Sema::CheckParmsForFunctionDef(FunctionDecl *FD) { + bool HasInvalidParm = false; + for (unsigned p = 0, NumParams = FD->getNumParams(); p < NumParams; ++p) { + ParmVarDecl *Param = FD->getParamDecl(p); + + // C99 6.7.5.3p4: the parameters in a parameter type list in a + // function declarator that is part of a function definition of + // that function shall not have incomplete type. + if (Param->getType()->isIncompleteType() && + !Param->isInvalidDecl()) { + Diag(Param->getLocation(), diag::err_typecheck_decl_incomplete_type, + Param->getType().getAsString()); + Param->setInvalidDecl(); + HasInvalidParm = true; + } + } + + return HasInvalidParm; +} + +/// CreateImplicitParameter - Creates an implicit function parameter +/// in the scope S and with the given type. This routine is used, for +/// example, to create the implicit "self" parameter in an Objective-C +/// method. +ParmVarDecl * +Sema::CreateImplicitParameter(Scope *S, IdentifierInfo *Id, + SourceLocation IdLoc, QualType Type) { + ParmVarDecl *New = ParmVarDecl::Create(Context, CurContext, IdLoc, Id, Type, + VarDecl::None, 0, 0); + if (Id) { + New->setNext(Id->getFETokenInfo()); + Id->setFETokenInfo(New); + S->AddDecl(New); + } + + return New; +} + /// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with /// no declarator (e.g. "struct foo;") is parsed. Sema::DeclTy *Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) { @@ -769,7 +820,38 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) { // Handle attributes. HandleDeclAttributes(NewFD, D.getDeclSpec().getAttributes(), D.getAttributes()); - + + // Copy the parameter declarations from the declarator D to + // the function declaration NewFD, if they are available. + if (D.getNumTypeObjects() > 0 && + D.getTypeObject(0).Fun.hasPrototype) { + DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun; + + // Create Decl objects for each parameter, adding them to the + // FunctionDecl. + llvm::SmallVector Params; + + // Check for C99 6.7.5.3p10 - foo(void) is a non-varargs + // function that takes no arguments, not a function that takes a + // single void argument. FIXME: Is this really the right place + // to check for this? C++ says that the parameter list (void) is + // the same as an empty parameter list, whereas the parameter + // list (T) (with T typedef'd to void) is not. For C++, this + // should be handled in the parser. Check C89 and C99 standards + // to see what the correct behavior is. + if (FTI.NumArgs == 1 && !FTI.isVariadic && FTI.ArgInfo[0].Ident == 0 && + FTI.ArgInfo[0].Param && + !((ParmVarDecl*)FTI.ArgInfo[0].Param)->getType().getCVRQualifiers() && + ((ParmVarDecl*)FTI.ArgInfo[0].Param)->getType()->isVoidType()) { + // empty arg list, don't push any params. + } else { + for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) + Params.push_back((ParmVarDecl *)FTI.ArgInfo[i].Param); + } + + NewFD->setParams(&Params[0], Params.size()); + } + // Merge the decl with the existing one if appropriate. Since C functions // are in a flat namespace, make sure we consider decls in outer scopes. if (PrevDecl) { @@ -777,6 +859,10 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) { if (NewFD == 0) return 0; } New = NewFD; + + // In C++, check default arguments now that we have merged decls. + if (getLangOptions().CPlusPlus) + CheckCXXDefaultArguments(NewFD); } else { if (R.getTypePtr()->isObjCInterfaceType()) { Diag(D.getIdentifierLoc(), diag::err_statically_allocated_object, @@ -982,20 +1068,47 @@ Sema::DeclTy *Sema::FinalizeDeclaratorGroup(Scope *S, DeclTy *group) { return NewGroup; } -// Called from Sema::ParseStartOfFunctionDef(). -ParmVarDecl * -Sema::ActOnParamDeclarator(struct DeclaratorChunk::ParamInfo &PI, - Scope *FnScope) { - IdentifierInfo *II = PI.Ident; +/// ActOnParamDeclarator - Called from Parser::ParseFunctionDeclarator() +/// to introduce parameters into function prototype scope. +Sema::DeclTy * +Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { + DeclSpec &DS = D.getDeclSpec(); + + // Verify C99 6.7.5.3p2: The only SCS allowed is 'register'. + if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified && + DS.getStorageClassSpec() != DeclSpec::SCS_register) { + Diag(DS.getStorageClassSpecLoc(), + diag::err_invalid_storage_class_in_func_decl); + DS.ClearStorageClassSpecs(); + } + if (DS.isThreadSpecified()) { + Diag(DS.getThreadSpecLoc(), + diag::err_invalid_storage_class_in_func_decl); + DS.ClearStorageClassSpecs(); + } + + + // In this context, we *do not* check D.getInvalidType(). If the declarator + // type was invalid, GetTypeForDeclarator() still returns a "valid" type, + // though it will not reflect the user specified type. + QualType parmDeclType = GetTypeForDeclarator(D, S); + + assert(!parmDeclType.isNull() && "GetTypeForDeclarator() returned null type"); + // TODO: CHECK FOR CONFLICTS, multiple decls with same name in one scope. // Can this happen for params? We already checked that they don't conflict // among each other. Here they can only shadow globals, which is ok. - if (/*Decl *PrevDecl = */LookupDecl(II, Decl::IDNS_Ordinary, FnScope)) { - + IdentifierInfo *II = D.getIdentifier(); + if (Decl *PrevDecl = LookupDecl(II, Decl::IDNS_Ordinary, S)) { + if (S->isDeclScope(PrevDecl)) { + Diag(D.getIdentifierLoc(), diag::err_param_redefinition, + dyn_cast(PrevDecl)->getName()); + + // Recover by removing the name + II = 0; + D.SetIdentifier(0, D.getIdentifierLoc()); + } } - - // FIXME: Handle storage class (auto, register). No declarator? - // TODO: Chain to previous parameter with the prevdeclarator chain? // Perform the default function/array conversion (C99 6.7.5.3p[7,8]). // Doing the promotion here has a win and a loss. The win is the type for @@ -1014,29 +1127,29 @@ Sema::ActOnParamDeclarator(struct DeclaratorChunk::ParamInfo &PI, // FIXME: If a source translation tool needs to see the original type, then // we need to consider storing both types (in ParmVarDecl)... // - QualType parmDeclType = QualType::getFromOpaquePtr(PI.TypeInfo); if (parmDeclType->isArrayType()) { // int x[restrict 4] -> int *restrict parmDeclType = Context.getArrayDecayedType(parmDeclType); } else if (parmDeclType->isFunctionType()) parmDeclType = Context.getPointerType(parmDeclType); - ParmVarDecl *New = ParmVarDecl::Create(Context, CurContext, PI.IdentLoc, II, - parmDeclType, - VarDecl::None, 0); + ParmVarDecl *New = ParmVarDecl::Create(Context, CurContext, + D.getIdentifierLoc(), II, + parmDeclType, VarDecl::None, + 0, 0); - if (PI.InvalidType) + if (D.getInvalidType()) New->setInvalidDecl(); - // If this has an identifier, add it to the scope stack. if (II) { New->setNext(II->getFETokenInfo()); II->setFETokenInfo(New); - FnScope->AddDecl(New); + S->AddDecl(New); } - HandleDeclAttributes(New, PI.AttrList, 0); + HandleDeclAttributes(New, D.getAttributes(), 0); return New; + } Sema::DeclTy *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D) { @@ -1044,17 +1157,23 @@ Sema::DeclTy *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D) { assert(D.getTypeObject(0).Kind == DeclaratorChunk::Function && "Not a function declarator!"); DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun; - + // Verify 6.9.1p6: 'every identifier in the identifier list shall be declared' // for a K&R function. if (!FTI.hasPrototype) { for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) { - if (FTI.ArgInfo[i].TypeInfo == 0) { + if (FTI.ArgInfo[i].Param == 0) { Diag(FTI.ArgInfo[i].IdentLoc, diag::ext_param_not_declared, FTI.ArgInfo[i].Ident->getName()); // Implicitly declare the argument as type 'int' for lack of a better // type. - FTI.ArgInfo[i].TypeInfo = Context.IntTy.getAsOpaquePtr(); + DeclSpec DS; + const char* PrevSpec; // unused + DS.SetTypeSpecType(DeclSpec::TST_int, FTI.ArgInfo[i].IdentLoc, + PrevSpec); + Declarator ParamD(DS, Declarator::KNRTypeListContext); + ParamD.SetIdentifier(FTI.ArgInfo[i].Ident, FTI.ArgInfo[i].IdentLoc); + FTI.ArgInfo[i].Param = ActOnParamDeclarator(FnBodyScope, ParamD); } } @@ -1063,8 +1182,7 @@ Sema::DeclTy *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D) { if (FTI.NumArgs) FTI.hasPrototype = true; } else { - // FIXME: Diagnose arguments without names in C. - + // FIXME: Diagnose arguments without names in C. } Scope *GlobalScope = FnBodyScope->getParent(); @@ -1083,37 +1201,21 @@ Sema::DeclTy *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D) { FunctionDecl *FD = cast(decl); CurFunctionDecl = FD; PushDeclContext(FD); - - // Create Decl objects for each parameter, adding them to the FunctionDecl. - llvm::SmallVector Params; - - // Check for C99 6.7.5.3p10 - foo(void) is a non-varargs function that takes - // no arguments, not a function that takes a single void argument. - if (FTI.NumArgs == 1 && !FTI.isVariadic && FTI.ArgInfo[0].Ident == 0 && - !QualType::getFromOpaquePtr(FTI.ArgInfo[0].TypeInfo).getCVRQualifiers() && - QualType::getFromOpaquePtr(FTI.ArgInfo[0].TypeInfo)->isVoidType()) { - // empty arg list, don't push any params. - } else { - for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) { - ParmVarDecl *parmDecl; - - parmDecl = ActOnParamDeclarator(D.getTypeObject(0).Fun.ArgInfo[i], - FnBodyScope); - // C99 6.7.5.3p4: the parameters in a parameter type list in a function - // declarator that is part of a function definition of that function - // shall not have incomplete type. - if (parmDecl->getType()->isIncompleteType() && - !parmDecl->isInvalidDecl()) { - Diag(parmDecl->getLocation(), diag::err_typecheck_decl_incomplete_type, - parmDecl->getType().getAsString()); - parmDecl->setInvalidDecl(); - } - Params.push_back(parmDecl); + + // Check the validity of our function parameters + CheckParmsForFunctionDef(FD); + + // Introduce our parameters into the function scope + for (unsigned p = 0, NumParams = FD->getNumParams(); p < NumParams; ++p) { + ParmVarDecl *Param = FD->getParamDecl(p); + // If this has an identifier, add it to the scope stack. + if (IdentifierInfo *II = Param->getIdentifier()) { + Param->setNext(II->getFETokenInfo()); + II->setFETokenInfo(Param); + FnBodyScope->AddDecl(Param); } } - - FD->setParams(&Params[0], Params.size()); - + return FD; } diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index c94c681fcb..a9efe6c251 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -42,32 +42,31 @@ void Sema::ObjCActOnStartOfMethodDef(Scope *FnBodyScope, DeclTy *D) { // Insert the invisible arguments, self and _cmd! PI.Ident = &Context.Idents.get("self"); PI.IdentLoc = SourceLocation(); // synthesized vars have a null location. - PI.InvalidType = false; - PI.AttrList = 0; - PI.TypeInfo = Context.getObjCIdType().getAsOpaquePtr(); - + QualType selfTy = Context.getObjCIdType(); if (MDecl->isInstance()) { if (ObjCInterfaceDecl *OID = MDecl->getClassInterface()) { // There may be no interface context due to error in declaration of the // interface (which has been reported). Recover gracefully - QualType selfTy = Context.getObjCInterfaceType(OID); + selfTy = Context.getObjCInterfaceType(OID); selfTy = Context.getPointerType(selfTy); - PI.TypeInfo = selfTy.getAsOpaquePtr(); } } - - CurMethodDecl->setSelfDecl(ActOnParamDeclarator(PI, FnBodyScope)); + CurMethodDecl->setSelfDecl(CreateImplicitParameter(FnBodyScope, PI.Ident, + PI.IdentLoc, selfTy)); PI.Ident = &Context.Idents.get("_cmd"); - PI.TypeInfo = Context.getObjCSelType().getAsOpaquePtr(); - ActOnParamDeclarator(PI, FnBodyScope); - + CreateImplicitParameter(FnBodyScope, PI.Ident, PI.IdentLoc, + Context.getObjCSelType()); + + // Introduce all of the othe parameters into this scope for (unsigned i = 0, e = MDecl->getNumParams(); i != e; ++i) { ParmVarDecl *PDecl = MDecl->getParamDecl(i); - PI.Ident = PDecl->getIdentifier(); - PI.IdentLoc = PDecl->getLocation(); // user vars have a real location. - PI.TypeInfo = PDecl->getType().getAsOpaquePtr(); - MDecl->setParamDecl(i, ActOnParamDeclarator(PI, FnBodyScope)); + IdentifierInfo *II = PDecl->getIdentifier(); + if (II) { + PDecl->setNext(II->getFETokenInfo()); + II->setFETokenInfo(PDecl); + FnBodyScope->AddDecl(PDecl); + } } } @@ -843,7 +842,7 @@ Sema::DeclTy *Sema::ActOnMethodDeclaration( ParmVarDecl* Param = ParmVarDecl::Create(Context, ObjCMethod, SourceLocation(/*FIXME*/), ArgNames[i], argType, - VarDecl::None, 0); + VarDecl::None, 0, 0); Param->setObjCDeclQualifier( CvtQTToAstBitMask(ArgQT[i].getObjCDeclQualifier())); Params.push_back(Param); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index f4ef283985..6a6cd25575 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -15,6 +15,7 @@ #include "SemaUtil.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" #include "clang/Parse/DeclSpec.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/LiteralSupport.h" @@ -594,15 +595,25 @@ ActOnCallExpr(ExprTy *fn, SourceLocation LParenLoc, Expr *Fn = static_cast(fn); Expr **Args = reinterpret_cast(args); assert(Fn && "no function call expression"); - + FunctionDecl *FDecl = NULL; + unsigned NumArgsPassed = NumArgs; + + // Promote the function operand. + UsualUnaryConversions(Fn); + + // If we're directly calling a function, get the declaration for + // that function. + if (ImplicitCastExpr *IcExpr = dyn_cast(Fn)) + if (DeclRefExpr *DRExpr = dyn_cast(IcExpr->getSubExpr())) + FDecl = dyn_cast(DRExpr->getDecl()); + // Make the call expr early, before semantic checks. This guarantees cleanup // of arguments and function on error. - llvm::OwningPtr TheCall(new CallExpr(Fn, Args, NumArgs, + if (getLangOptions().CPlusPlus && FDecl && NumArgs < FDecl->getNumParams()) + NumArgsPassed = FDecl->getNumParams(); + llvm::OwningPtr TheCall(new CallExpr(Fn, Args, NumArgsPassed, Context.BoolTy, RParenLoc)); - // Promote the function operand. - TheCall->setCallee(UsualUnaryConversions(Fn)); - // C99 6.5.2.2p1 - "The expression that denotes the called function shall have // type pointer to function". const PointerType *PT = Fn->getType()->getAsPointerType(); @@ -623,11 +634,19 @@ ActOnCallExpr(ExprTy *fn, SourceLocation LParenLoc, unsigned NumArgsInProto = Proto->getNumArgs(); unsigned NumArgsToCheck = NumArgs; - // If too few arguments are available, don't make the call. - if (NumArgs < NumArgsInProto) - return Diag(RParenLoc, diag::err_typecheck_call_too_few_args, - Fn->getSourceRange()); - + // If too few arguments are available (and we don't have default + // arguments for the remaining parameters), don't make the call. + if (NumArgs < NumArgsInProto) { + if (getLangOptions().CPlusPlus && + FDecl && + FDecl->getParamDecl(NumArgs)->getDefaultArg()) { + // Use default arguments for missing arguments + NumArgsToCheck = NumArgsInProto; + } else + return Diag(RParenLoc, diag::err_typecheck_call_too_few_args, + Fn->getSourceRange()); + } + // If too many are passed and not variadic, error on the extras and drop // them. if (NumArgs > NumArgsInProto) { @@ -644,8 +663,13 @@ ActOnCallExpr(ExprTy *fn, SourceLocation LParenLoc, // Continue to check argument types (even if we have too few/many args). for (unsigned i = 0; i != NumArgsToCheck; i++) { - Expr *Arg = Args[i]; QualType ProtoArgType = Proto->getArgType(i); + + Expr *Arg; + if (i < NumArgs) + Arg = Args[i]; + else + Arg = new CXXDefaultArgExpr(FDecl->getParamDecl(i)); QualType ArgType = Arg->getType(); // Compute implicit casts from the operand to the formal argument type. @@ -679,11 +703,8 @@ ActOnCallExpr(ExprTy *fn, SourceLocation LParenLoc, } // Do special checking on direct calls to functions. - if (ImplicitCastExpr *IcExpr = dyn_cast(Fn)) - if (DeclRefExpr *DRExpr = dyn_cast(IcExpr->getSubExpr())) - if (FunctionDecl *FDecl = dyn_cast(DRExpr->getDecl())) - if (CheckFunctionCall(FDecl, TheCall.get())) - return true; + if (FDecl && CheckFunctionCall(FDecl, TheCall.get())) + return true; return TheCall.take(); } diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 725da22334..4393b80a66 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -394,7 +394,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S) { llvm::SmallVector ArgTys; for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) { - QualType ArgTy = QualType::getFromOpaquePtr(FTI.ArgInfo[i].TypeInfo); + QualType ArgTy = ((ParmVarDecl *)FTI.ArgInfo[i].Param)->getType(); assert(!ArgTy.isNull() && "Couldn't parse type?"); // // Perform the default function/array conversion (C99 6.7.5.3p[7,8]). @@ -425,13 +425,13 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S) { if (FTI.NumArgs != 1 || FTI.isVariadic) { Diag(DeclType.Loc, diag::err_void_only_param); ArgTy = Context.IntTy; - FTI.ArgInfo[i].TypeInfo = ArgTy.getAsOpaquePtr(); + ((ParmVarDecl *)FTI.ArgInfo[i].Param)->setType(ArgTy); } else if (FTI.ArgInfo[i].Ident) { // Reject, but continue to parse 'int(void abc)'. Diag(FTI.ArgInfo[i].IdentLoc, diag::err_param_with_void_type); ArgTy = Context.IntTy; - FTI.ArgInfo[i].TypeInfo = ArgTy.getAsOpaquePtr(); + ((ParmVarDecl *)FTI.ArgInfo[i].Param)->setType(ArgTy); } else { // Reject, but continue to parse 'float(const void)'. if (ArgTy.getCVRQualifiers()) @@ -504,39 +504,6 @@ Sema::TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) { return T.getAsOpaquePtr(); } -/// ActOnParamDeclaratorType - Called from Parser::ParseFunctionDeclarator() -/// when analyzing function prototypes. -/// -/// Note: parameters have identifiers, but we don't care about them here, we -/// just want the type converted. -/// -Sema::TypeResult Sema::ActOnParamDeclaratorType(Scope *S, Declarator &D) { - DeclSpec &DS = D.getDeclSpec(); - - // Verify C99 6.7.5.3p2: The only SCS allowed is 'register'. - if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified && - DS.getStorageClassSpec() != DeclSpec::SCS_register) { - Diag(DS.getStorageClassSpecLoc(), - diag::err_invalid_storage_class_in_func_decl); - DS.ClearStorageClassSpecs(); - } - if (DS.isThreadSpecified()) { - Diag(DS.getThreadSpecLoc(), - diag::err_invalid_storage_class_in_func_decl); - DS.ClearStorageClassSpecs(); - } - - - QualType T = GetTypeForDeclarator(D, S); - - assert(!T.isNull() && "GetTypeForDeclarator() returned null type"); - - // In this context, we *do not* check D.getInvalidType(). If the declarator - // type was invalid, GetTypeForDeclarator() still returns a "valid" type, - // though it will not reflect the user specified type. - return T.getAsOpaquePtr(); -} - AttributeList *Sema::ProcessTypeAttributes(QualType &Result, AttributeList *AL){ // Scan through and apply attributes to this type where it makes sense. Some // attributes (such as __address_space__, __vector_size__, etc) apply to the diff --git a/test/CodeGen/cxx-default-arg.cpp b/test/CodeGen/cxx-default-arg.cpp new file mode 100644 index 0000000000..957b60a8d7 --- /dev/null +++ b/test/CodeGen/cxx-default-arg.cpp @@ -0,0 +1,25 @@ +// RUN: clang -emit-llvm %s + +// Note: define CLANG_GENERATE_KNOWN_GOOD and compile to generate code +// that makes all of the defaulted arguments explicit. The resulting +// byte code should be identical to the compilation without +// CLANG_GENERATE_KNOWN_GOOD. +#ifdef CLANG_GENERATE_KNOWN_GOOD +# define DEFARG(...) __VA_ARGS__ +#else +# define DEFARG(...) +#endif + +extern int x; +struct S { float x; float y; } s; +double _Complex c; + +void f(int i = 0, int j = 1, int k = x, struct S t = s, double _Complex d = c); + +void g() { + f(0, 1, x, s DEFARG(, c)); + f(0, 1, x DEFARG(, s, c)); + f(0, 1 DEFARG(, x, s, c)); + f(0 DEFARG(, 1, x, s, c)); + f(DEFARG(0, 1, x, s, c)); +} diff --git a/test/Sema/arg-scope-c99.c b/test/Sema/arg-scope-c99.c new file mode 100644 index 0000000000..2d386c45da --- /dev/null +++ b/test/Sema/arg-scope-c99.c @@ -0,0 +1,2 @@ +// RUN: clang -fsyntax-only -std=c99 -verify %s +int bb(int sz, int ar[sz][sz]) { } diff --git a/test/Sema/arg-scope.c b/test/Sema/arg-scope.c new file mode 100644 index 0000000000..fc2bb70d0a --- /dev/null +++ b/test/Sema/arg-scope.c @@ -0,0 +1,5 @@ +// RUN: clang -fsyntax-only -verify %s +int aa(int b, int x[sizeof b]) {} + +void foo(int i, int A[i]) {} + diff --git a/test/Sema/default1.c b/test/Sema/default1.c new file mode 100644 index 0000000000..a72d0aef0c --- /dev/null +++ b/test/Sema/default1.c @@ -0,0 +1,2 @@ +// RUN: clang -fsyntax-only -verify %s +void f(int i = 0); // expected-error {{C does not support default arguments}} diff --git a/test/Sema/default1.cpp b/test/Sema/default1.cpp new file mode 100644 index 0000000000..fe019c847a --- /dev/null +++ b/test/Sema/default1.cpp @@ -0,0 +1,17 @@ +// RUN: clang -fsyntax-only -verify %s +void f(int i); +void f(int i = 0); // expected-error {{previous definition is here}} +void f(int i = 17); // expected-error {{redefinition of default argument}} + + +void g(int i, int j, int k = 3); +void g(int i, int j = 2, int k); +void g(int i = 1, int j, int k); + +void h(int i, int j = 2, int k = 3, + int l, // expected-error {{missing default argument on parameter 'l'}} + int, // expected-error {{missing default argument on parameter}} + int n);// expected-error {{missing default argument on parameter 'n'}} + +struct S { } s; +void i(int = s) { } // expected-error {{incompatible type}} diff --git a/test/Sema/default2.cpp b/test/Sema/default2.cpp new file mode 100644 index 0000000000..0fe04abc79 --- /dev/null +++ b/test/Sema/default2.cpp @@ -0,0 +1,12 @@ +// RUN: clang -fsyntax-only -verify %s +void f(int i, int j, int k = 3); +void f(int i, int j = 2, int k); +void f(int i = 1, int j, int k); + +void i() +{ + f(); + f(0); + f(0, 1); + f(0, 1, 2); +} -- 2.40.0