diff options
-rw-r--r-- | include/clang/AST/Decl.h | 21 | ||||
-rw-r--r-- | include/clang/AST/ExprCXX.h | 4 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticKinds.def | 4 | ||||
-rw-r--r-- | include/clang/Parse/Action.h | 7 | ||||
-rw-r--r-- | lib/AST/StmtDumper.cpp | 14 | ||||
-rw-r--r-- | lib/AST/Type.cpp | 2 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 8 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 2 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 11 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 45 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 15 | ||||
-rw-r--r-- | test/SemaCXX/condition.cpp | 4 | ||||
-rw-r--r-- | test/SemaCXX/constructor.cpp | 5 | ||||
-rw-r--r-- | test/SemaCXX/copy-initialization.cpp | 2 | ||||
-rw-r--r-- | test/SemaCXX/default1.cpp | 4 | ||||
-rw-r--r-- | test/SemaCXX/default2.cpp | 12 |
16 files changed, 124 insertions, 36 deletions
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 8ff8aefaaf..0401c50454 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -504,6 +504,27 @@ public: Expr *getDefaultArg() { return DefaultArg; } void setDefaultArg(Expr *defarg) { DefaultArg = defarg; } + /// hasUnparsedDefaultArg - Determines whether this parameter has a + /// default argument that has not yet been parsed. This will occur + /// during the processing of a C++ class whose member functions have + /// default arguments, e.g., + /// @code + /// class X { + /// public: + /// void f(int x = 17); // x has an unparsed default argument now + /// }; // x has a regular default argument now + /// @endcode + bool hasUnparsedDefaultArg() const { + return DefaultArg == reinterpret_cast<Expr *>(-1); + } + + /// setUnparsedDefaultArg - Specify that this parameter has an + /// unparsed default argument. The argument will be replaced with a + /// real default argument via setDefaultArg when the class + /// definition enclosing the function declaration that owns this + /// default argument is completed. + void setUnparsedDefaultArg() { DefaultArg = reinterpret_cast<Expr *>(-1); } + QualType getOriginalType() const; // Implement isa/cast/dyncast/etc. diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index 31dfd25833..be33eb1939 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -335,7 +335,9 @@ public: // Param is the parameter whose default argument is used by this // expression. explicit CXXDefaultArgExpr(ParmVarDecl *param) - : Expr(CXXDefaultArgExprClass, param->getDefaultArg()->getType()), + : Expr(CXXDefaultArgExprClass, + param->hasUnparsedDefaultArg()? param->getType().getNonReferenceType() + : param->getDefaultArg()->getType()), Param(param) { } // Retrieve the parameter that the argument was created from. diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index 7675710a34..321b2c69c5 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -1352,6 +1352,10 @@ DIAG(warn_value_always_false, WARNING, // FIXME: %2 is an english string here. DIAG(err_typecheck_convert_incompatible, ERROR, "incompatible type %2 %1, expected %0") +DIAG(err_cannot_initialize_decl_noname, ERROR, + "cannot initialize a value of type %0 with an %select{rvalue|lvalue}1 of type %2") +DIAG(err_cannot_initialize_decl, ERROR, + "cannot initialize %0 with an %select{rvalue|lvalue}1 of type %2") DIAG(warn_incompatible_qualified_id, WARNING, "incompatible type %2 %1, expected %0") DIAG(warn_incompatible_qualified_id_operands, WARNING, diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index 39de870d12..13b3c8a2b7 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -734,6 +734,13 @@ public: ExprTy *defarg) { } + /// ActOnParamUnparsedDefaultArgument - We've seen a default + /// argument for a function parameter, but we can't parse it yet + /// because we're inside a class definition. Note that this default + /// argument will be parsed later. + virtual void ActOnParamUnparsedDefaultArgument(DeclTy *param, + SourceLocation EqualLoc) { } + /// ActOnParamDefaultArgumentError - Parsing or semantic analysis of /// the default argument for the parameter param failed. virtual void ActOnParamDefaultArgumentError(DeclTy *param) { } diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp index f11536f9c2..c3ce92de60 100644 --- a/lib/AST/StmtDumper.cpp +++ b/lib/AST/StmtDumper.cpp @@ -83,12 +83,14 @@ namespace { void DumpType(QualType T) { fprintf(F, "'%s'", T.getAsString().c_str()); - // If the type is directly a typedef, strip off typedefness to give at - // least one level of concreteness. - if (TypedefType *TDT = dyn_cast<TypedefType>(T)) { - QualType Simplified = - TDT->LookThroughTypedefs().getQualifiedType(T.getCVRQualifiers()); - fprintf(F, ":'%s'", Simplified.getAsString().c_str()); + if (!T.isNull()) { + // If the type is directly a typedef, strip off typedefness to give at + // least one level of concreteness. + if (TypedefType *TDT = dyn_cast<TypedefType>(T)) { + QualType Simplified = + TDT->LookThroughTypedefs().getQualifiedType(T.getCVRQualifiers()); + fprintf(F, ":'%s'", Simplified.getAsString().c_str()); + } } } void DumpStmt(const Stmt *Node) { diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 5909c976aa..c70ad4af52 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -841,7 +841,7 @@ static void AppendTypeQualList(std::string &S, unsigned TypeQuals) { void QualType::getAsStringInternal(std::string &S) const { if (isNull()) { - S += "NULL TYPE\n"; + S += "NULL TYPE"; return; } diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 16e7e774aa..213a210b9e 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -1811,6 +1811,8 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, // ActOnParamDefaultArgument will reject the default argument in // C. if (Tok.is(tok::equal)) { + SourceLocation EqualLoc = Tok.getLocation(); + // Parse the default argument if (D.getContext() == Declarator::MemberContext) { // If we're inside a class definition, cache the tokens @@ -1824,10 +1826,12 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, tok::semi, false)) { delete DefArgToks; DefArgToks = 0; - } + Actions.ActOnParamDefaultArgumentError(Param); + } else + Actions.ActOnParamUnparsedDefaultArgument(Param, EqualLoc); } else { // Consume the '='. - SourceLocation EqualLoc = ConsumeToken(); + ConsumeToken(); OwningExprResult DefArgResult(ParseAssignmentExpression()); if (DefArgResult.isInvalid()) { diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 2664c57ee4..843e732e87 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -276,6 +276,8 @@ public: virtual void ActOnParamDefaultArgument(DeclTy *param, SourceLocation EqualLoc, ExprTy *defarg); + virtual void ActOnParamUnparsedDefaultArgument(DeclTy *param, + SourceLocation EqualLoc); virtual void ActOnParamDefaultArgumentError(DeclTy *param); void AddInitializerToDecl(DeclTy *dcl, ExprArg init); void ActOnUninitializedDecl(DeclTy *dcl); diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index d84d6adad0..c668959176 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -888,9 +888,14 @@ bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType, if (!PerformImplicitConversion(Init, DeclType, "initializing")) return false; - return Diag(InitLoc, diag::err_typecheck_convert_incompatible) - << DeclType << InitEntity << "initializing" - << Init->getSourceRange(); + if (InitEntity) + return Diag(InitLoc, diag::err_cannot_initialize_decl) + << InitEntity << (int)(Init->isLvalue(Context) == Expr::LV_Valid) + << Init->getType() << Init->getSourceRange(); + else + return Diag(InitLoc, diag::err_cannot_initialize_decl_noname) + << DeclType << (int)(Init->isLvalue(Context) == Expr::LV_Valid) + << Init->getType() << Init->getSourceRange(); } // C99 6.7.8p16. diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 918fd2ac9a..48373369bc 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -126,8 +126,9 @@ Sema::ActOnParamDefaultArgument(DeclTy *param, SourceLocation EqualLoc, // a declaration of a variable of the parameter type, using the // copy-initialization semantics (8.5). Expr *DefaultArgPtr = DefaultArg.get(); - bool DefaultInitFailed = PerformCopyInitialization(DefaultArgPtr, ParamType, - "in default argument"); + bool DefaultInitFailed = CheckInitializerTypes(DefaultArgPtr, ParamType, + EqualLoc, + Param->getDeclName()); if (DefaultArgPtr != DefaultArg.get()) { DefaultArg.take(); DefaultArg.reset(DefaultArgPtr); @@ -147,6 +148,17 @@ Sema::ActOnParamDefaultArgument(DeclTy *param, SourceLocation EqualLoc, Param->setDefaultArg(DefaultArg.take()); } +/// ActOnParamUnparsedDefaultArgument - We've seen a default +/// argument for a function parameter, but we can't parse it yet +/// because we're inside a class definition. Note that this default +/// argument will be parsed later. +void Sema::ActOnParamUnparsedDefaultArgument(DeclTy *param, + SourceLocation EqualLoc) { + ParmVarDecl *Param = (ParmVarDecl*)param; + if (Param) + Param->setUnparsedDefaultArg(); +} + /// ActOnParamDefaultArgumentError - Parsing or semantic analysis of /// the default argument for the parameter param failed. void Sema::ActOnParamDefaultArgumentError(DeclTy *param) { @@ -171,16 +183,16 @@ void Sema::CheckExtraCXXDefaultArguments(Declarator &D) { if (chunk.Kind == DeclaratorChunk::Function) { for (unsigned argIdx = 0; argIdx < chunk.Fun.NumArgs; ++argIdx) { ParmVarDecl *Param = (ParmVarDecl *)chunk.Fun.ArgInfo[argIdx].Param; - if (Param->getDefaultArg()) { - Diag(Param->getLocation(), diag::err_param_default_argument_nonfunc) - << Param->getDefaultArg()->getSourceRange(); - Param->setDefaultArg(0); - } else if (CachedTokens *Toks - = chunk.Fun.ArgInfo[argIdx].DefaultArgTokens) { + if (Param->hasUnparsedDefaultArg()) { + CachedTokens *Toks = chunk.Fun.ArgInfo[argIdx].DefaultArgTokens; Diag(Param->getLocation(), diag::err_param_default_argument_nonfunc) << SourceRange((*Toks)[1].getLocation(), Toks->back().getLocation()); delete Toks; chunk.Fun.ArgInfo[argIdx].DefaultArgTokens = 0; + } else if (Param->getDefaultArg()) { + Diag(Param->getLocation(), diag::err_param_default_argument_nonfunc) + << Param->getDefaultArg()->getSourceRange(); + Param->setDefaultArg(0); } } } @@ -269,7 +281,8 @@ void Sema::CheckCXXDefaultArguments(FunctionDecl *FD) { for (p = 0; p <= LastMissingDefaultArg; ++p) { ParmVarDecl *Param = FD->getParamDecl(p); if (Param->getDefaultArg()) { - delete Param->getDefaultArg(); + if (!Param->hasUnparsedDefaultArg()) + Param->getDefaultArg()->Destroy(Context); Param->setDefaultArg(0); } } @@ -736,6 +749,7 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, ActOnFields(S, RLoc, TagDecl, (DeclTy**)FieldCollector->getCurFields(), FieldCollector->getCurNumFields(), LBrac, RBrac, 0); + AddImplicitlyDeclaredMembersToClass(cast<CXXRecordDecl>((Decl*)TagDecl)); } /// AddImplicitlyDeclaredMembersToClass - Adds any implicitly-declared @@ -872,7 +886,6 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { void Sema::ActOnFinishCXXClassDef(DeclTy *D) { CXXRecordDecl *Rec = cast<CXXRecordDecl>(static_cast<Decl *>(D)); FieldCollector->FinishClass(); - AddImplicitlyDeclaredMembersToClass(Rec); PopDeclContext(); // Everything, including inline method definitions, have been parsed. @@ -901,6 +914,12 @@ void Sema::ActOnStartDelayedCXXMethodDeclaration(Scope *S, DeclTy *Method) { /// ActOnParamDefaultArgument event for this parameter. void Sema::ActOnDelayedCXXMethodParameter(Scope *S, DeclTy *ParamD) { ParmVarDecl *Param = (ParmVarDecl*)ParamD; + + // If this parameter has an unparsed default argument, clear it out + // to make way for the parsed default argument. + if (Param->hasUnparsedDefaultArg()) + Param->setDefaultArg(0); + S->AddDecl(Param); if (Param->getDeclName()) IdResolver.AddDecl(Param); @@ -1871,7 +1890,11 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) { if (Op != OO_Call) { for (FunctionDecl::param_iterator Param = FnDecl->param_begin(); Param != FnDecl->param_end(); ++Param) { - if (Expr *DefArg = (*Param)->getDefaultArg()) + if ((*Param)->hasUnparsedDefaultArg()) + return Diag((*Param)->getLocation(), + diag::err_operator_overload_default_arg) + << FnDecl->getDeclName(); + else if (Expr *DefArg = (*Param)->getDefaultArg()) return Diag((*Param)->getLocation(), diag::err_operator_overload_default_arg) << FnDecl->getDeclName() << DefArg->getSourceRange(); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 4088f443f7..d65c10bb50 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -1507,16 +1507,17 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, QualType ProtoArgType = Proto->getArgType(i); Expr *Arg; - if (i < NumArgs) + if (i < NumArgs) { Arg = Args[i]; - else + + // Pass the argument. + if (PerformCopyInitialization(Arg, ProtoArgType, "passing")) + return true; + } else + // We already type-checked the argument, so we know it works. Arg = new CXXDefaultArgExpr(FDecl->getParamDecl(i)); QualType ArgType = Arg->getType(); - - // Pass the argument. - if (PerformCopyInitialization(Arg, ProtoArgType, "passing")) - return true; - + Call->setArg(i, Arg); } diff --git a/test/SemaCXX/condition.cpp b/test/SemaCXX/condition.cpp index d611364cf0..43117e61c3 100644 --- a/test/SemaCXX/condition.cpp +++ b/test/SemaCXX/condition.cpp @@ -16,8 +16,8 @@ void test() { for (;s;) ; // expected-error {{expression must have bool type (or be convertible to bool) ('struct S' invalid)}} switch (s) {} // expected-error {{statement requires expression of integer type ('struct S' invalid)}} - while (struct S {} x=0) ; // expected-error {{types may not be defined in conditions}} expected-error {{incompatible type}} expected-error {{expression must have bool type}} - while (struct {} x=0) ; // expected-error {{types may not be defined in conditions}} expected-error {{incompatible type}} expected-error {{expression must have bool type}} + while (struct S {} x=0) ; // expected-error {{types may not be defined in conditions}} expected-error {{cannot initialize 'x' with an rvalue of type 'int'}} expected-error {{expression must have bool type}} + while (struct {} x=0) ; // expected-error {{types may not be defined in conditions}} expected-error {{cannot initialize 'x' with an rvalue of type 'int'}} expected-error {{expression must have bool type}} switch (enum {E} x=0) ; // expected-error {{types may not be defined in conditions}} expected-error {{incompatible type}} if (int x=0) { // expected-note {{previous definition is here}} diff --git a/test/SemaCXX/constructor.cpp b/test/SemaCXX/constructor.cpp index 536593d512..68099ecac9 100644 --- a/test/SemaCXX/constructor.cpp +++ b/test/SemaCXX/constructor.cpp @@ -1,5 +1,4 @@ // RUN: clang -fsyntax-only -verify %s - typedef int INT; class Foo { @@ -37,3 +36,7 @@ struct y { y(int); }; extern y b; + +struct Length { + Length l() const { return *this; } +}; diff --git a/test/SemaCXX/copy-initialization.cpp b/test/SemaCXX/copy-initialization.cpp index 5ef84de9ac..e380cc1ad3 100644 --- a/test/SemaCXX/copy-initialization.cpp +++ b/test/SemaCXX/copy-initialization.cpp @@ -13,5 +13,5 @@ void f(Y y, int *ip, float *fp) { X x1 = y; // expected-error{{no matching constructor for initialization of 'x1'; candidate is:}} X x2 = 0; X x3 = ip; - X x4 = fp; // expected-error{{incompatible type initializing 'x4', expected 'class X'}} + X x4 = fp; // expected-error{{cannot initialize 'x4' with an lvalue of type 'float *'}} } diff --git a/test/SemaCXX/default1.cpp b/test/SemaCXX/default1.cpp index 286be6106b..28444207d8 100644 --- a/test/SemaCXX/default1.cpp +++ b/test/SemaCXX/default1.cpp @@ -26,4 +26,6 @@ struct Y { explicit Y(int); }; -void k(Y y = 17); // expected-error{{incompatible type in default argument}} +void k(Y y = 17); // expected-error{{cannot initialize 'y' with an rvalue of type 'int'}} + +void kk(Y = 17); // expected-error{{cannot initialize a value of type 'struct Y' with an rvalue of type 'int'}} diff --git a/test/SemaCXX/default2.cpp b/test/SemaCXX/default2.cpp index 863ac0e25f..c2873af3f0 100644 --- a/test/SemaCXX/default2.cpp +++ b/test/SemaCXX/default2.cpp @@ -103,8 +103,20 @@ public: Z z2; // expected-error{{no matching constructor for initialization}} Z z3(z); } + + void test_Z(const Z& z) { + Z z2(z); // expected-error{{no matching constructor for initialization of 'z2'}} + } }; void test_Z(const Z& z) { Z z2(z); // expected-error{{no matching constructor for initialization of 'z2'}} } + +struct ZZ { + void f(ZZ z = g()); // expected-error{{no matching constructor for initialization}} + + static ZZ g(int = 17); + + ZZ(ZZ&, int = 17); // expected-note{{candidate function}} +}; |