diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-08-22 00:34:47 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-08-22 00:34:47 +0000 |
commit | d83d04041f64a2c89123d227fa8003b482391279 (patch) | |
tree | cff3c814385b448dfc048774b1ba787dfd188f0b | |
parent | c141086bff9c2809aa46efdc5ce66756430f3470 (diff) |
Implement delayed parsing for member function templates. Fixes PR4608.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@79709 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/Parse/Parser.h | 16 | ||||
-rw-r--r-- | lib/Parse/ParseCXXInlineMethods.cpp | 15 | ||||
-rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 1 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 20 | ||||
-rw-r--r-- | test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p4.cpp | 20 | ||||
-rw-r--r-- | test/SemaTemplate/member-function-template.cpp | 3 |
6 files changed, 55 insertions, 20 deletions
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 2b48d9f212..ef8e48b7e6 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -462,7 +462,13 @@ private: struct LexedMethod { Action::DeclPtrTy D; CachedTokens Toks; - explicit LexedMethod(Action::DeclPtrTy MD) : D(MD) {} + + /// \brief Whether this member function had an associated template + /// scope. When true, D is a template declaration. + /// othewise, it is a member function declaration. + bool TemplateScope; + + explicit LexedMethod(Action::DeclPtrTy MD) : D(MD), TemplateScope(false) {} }; /// LateParsedDefaultArgument - Keeps track of a parameter that may @@ -489,11 +495,17 @@ private: /// until the class itself is completely-defined, such as a default /// argument (C++ [class.mem]p2). struct LateParsedMethodDeclaration { - explicit LateParsedMethodDeclaration(Action::DeclPtrTy M) : Method(M) { } + explicit LateParsedMethodDeclaration(Action::DeclPtrTy M) + : Method(M), TemplateScope(false) { } /// Method - The method declaration. Action::DeclPtrTy Method; + /// \brief Whether this member function had an associated template + /// scope. When true, D is a template declaration. + /// othewise, it is a member function declaration. + bool TemplateScope; + /// DefaultArgs - Contains the parameters of the function and /// their default arguments. At least one of the parameters will /// have a default argument, but all of the parameters of the diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp index 80feff42d7..f967c7a69d 100644 --- a/lib/Parse/ParseCXXInlineMethods.cpp +++ b/lib/Parse/ParseCXXInlineMethods.cpp @@ -44,6 +44,8 @@ Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D, // Consume the tokens and store them for later parsing. getCurrentClass().MethodDefs.push_back(LexedMethod(FnD)); + getCurrentClass().MethodDefs.back().TemplateScope + = CurScope->isTemplateParamScope(); CachedTokens &Toks = getCurrentClass().MethodDefs.back().Toks; tok::TokenKind kind = Tok.getKind(); @@ -99,9 +101,11 @@ void Parser::ParseLexedMethodDeclarations(ParsingClass &Class) { for (; !Class.MethodDecls.empty(); Class.MethodDecls.pop_front()) { LateParsedMethodDeclaration &LM = Class.MethodDecls.front(); - // FIXME: For member function templates, we'll need to introduce a - // scope for the template parameters. - + // If this is a member template, introduce the template parameter scope. + ParseScope TemplateScope(this, Scope::TemplateParamScope, LM.TemplateScope); + if (LM.TemplateScope) + Actions.ActOnReenterTemplateScope(CurScope, LM.Method); + // Start the delayed C++ method declaration Actions.ActOnStartDelayedCXXMethodDeclaration(CurScope, LM.Method); @@ -161,6 +165,11 @@ void Parser::ParseLexedMethodDefs(ParsingClass &Class) { for (; !Class.MethodDefs.empty(); Class.MethodDefs.pop_front()) { LexedMethod &LM = Class.MethodDefs.front(); + // If this is a member template, introduce the template parameter scope. + ParseScope TemplateScope(this, Scope::TemplateParamScope, LM.TemplateScope); + if (LM.TemplateScope) + Actions.ActOnReenterTemplateScope(CurScope, LM.D); + assert(!LM.Toks.empty() && "Empty body!"); // Append the current token at the end of the new token stream so that it // doesn't get lost. diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index bce9ee0d82..af4f83a505 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -861,6 +861,7 @@ void Parser::HandleMemberFunctionDefaultArgs(Declarator& DeclaratorInfo, getCurrentClass().MethodDecls.push_back( LateParsedMethodDeclaration(ThisDecl)); LateMethod = &getCurrentClass().MethodDecls.back(); + LateMethod->TemplateScope = CurScope->isTemplateParamScope(); // Add all of the parameters prior to this one (they don't // have default arguments). diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 4017772083..6668aeaac5 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -3526,7 +3526,13 @@ Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclPtrTy D) { if (!D) return D; - FunctionDecl *FD = cast<FunctionDecl>(D.getAs<Decl>()); + FunctionDecl *FD = 0; + + if (FunctionTemplateDecl *FunTmpl + = dyn_cast<FunctionTemplateDecl>(D.getAs<Decl>())) + FD = FunTmpl->getTemplatedDecl(); + else + FD = cast<FunctionDecl>(D.getAs<Decl>()); CurFunctionNeedsScopeChecking = false; @@ -3624,7 +3630,15 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg, bool IsInstantiation) { Decl *dcl = D.getAs<Decl>(); Stmt *Body = BodyArg.takeAs<Stmt>(); - if (FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(dcl)) { + + FunctionDecl *FD = 0; + FunctionTemplateDecl *FunTmpl = dyn_cast_or_null<FunctionTemplateDecl>(dcl); + if (FunTmpl) + FD = FunTmpl->getTemplatedDecl(); + else + FD = dyn_cast_or_null<FunctionDecl>(dcl); + + if (FD) { FD->setBody(Body); if (FD->isMain(Context)) // C and C++ allow for main to automagically return 0. @@ -3711,7 +3725,7 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg, // C++ constructors that have function-try-blocks can't have return // statements in the handlers of that block. (C++ [except.handle]p14) // Verify this. - if (isa<CXXConstructorDecl>(dcl) && isa<CXXTryStmt>(Body)) + if (FD && isa<CXXConstructorDecl>(FD) && isa<CXXTryStmt>(Body)) DiagnoseReturnInConstructorExceptionHandler(cast<CXXTryStmt>(Body)); if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(dcl)) diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p4.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p4.cpp index 439afa8c04..50d31fb2f8 100644 --- a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p4.cpp +++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p4.cpp @@ -11,36 +11,32 @@ void test_cvqual_ref(AnyT any) { struct AnyThreeLevelPtr { template<typename T> - operator T***() const; - // FIXME: Can't handle definitions of member templates yet -#if 0 + operator T***() const { T x = 0; - x = 0; // will fail if T is deduced to a const type + // FIXME: looks like we get this wrong, too! + // x = 0; // will fail if T is deduced to a const type // (EDG and GCC get this wrong) return 0; } -#endif }; +struct X { }; + void test_deduce_with_qual(AnyThreeLevelPtr a3) { int * const * const * const ip = a3; } -struct X { }; - struct AnyPtrMem { template<typename Class, typename T> - operator T Class::*() const; - // FIXME: Can't handle definitions of member templates yet -#if 0 + operator T Class::*() const { T x = 0; - x = 0; // will fail if T is deduced to a const type. + // FIXME: looks like we get this wrong, too! + // x = 0; // will fail if T is deduced to a const type. // (EDG and GCC get this wrong) return 0; } -#endif }; void test_deduce_ptrmem_with_qual(AnyPtrMem apm) { diff --git a/test/SemaTemplate/member-function-template.cpp b/test/SemaTemplate/member-function-template.cpp index 217a67a618..91eb53beff 100644 --- a/test/SemaTemplate/member-function-template.cpp +++ b/test/SemaTemplate/member-function-template.cpp @@ -39,3 +39,6 @@ void test_X_f1_address() { float& (X::*pm2)(float) = &X::f1; int& (X::*pm3)(float, int) = &X::f1; } + +// PR4608 +class A { template <class x> x a(x z) { return z+y; } int y; }; |