diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 1ae219781c69..dda6db131240 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -1088,12 +1088,40 @@ public: } }; + /// Introduces zero or more scopes for parsing. The scopes will all be exited + /// when the object is destroyed. + class MultiParseScope { + Parser &Self; + unsigned NumScopes = 0; + + MultiParseScope(const MultiParseScope&) = delete; + + public: + MultiParseScope(Parser &Self) : Self(Self) {} + void Enter(unsigned ScopeFlags) { + Self.EnterScope(ScopeFlags); + ++NumScopes; + } + void Exit() { + while (NumScopes) { + Self.ExitScope(); + --NumScopes; + } + } + ~MultiParseScope() { + Exit(); + } + }; + /// EnterScope - Start a new scope. void EnterScope(unsigned ScopeFlags); /// ExitScope - Pop a scope off the scope stack. void ExitScope(); + /// Re-enter the template scopes for a declaration that might be a template. + unsigned ReenterTemplateScopes(MultiParseScope &S, Decl *D); + private: /// RAII object used to modify the scope flags for the current scope. class ParseScopeFlags { @@ -1278,13 +1306,7 @@ private: Decl *D; CachedTokens Toks; - /// Whether this member function had an associated template - /// scope. When true, D is a template declaration. - /// otherwise, it is a member function declaration. - bool TemplateScope; - - explicit LexedMethod(Parser* P, Decl *MD) - : Self(P), D(MD), TemplateScope(false) {} + explicit LexedMethod(Parser *P, Decl *MD) : Self(P), D(MD) {} void ParseLexedMethodDefs() override; }; @@ -1314,8 +1336,7 @@ private: /// argument (C++ [class.mem]p2). struct LateParsedMethodDeclaration : public LateParsedDeclaration { explicit LateParsedMethodDeclaration(Parser *P, Decl *M) - : Self(P), Method(M), TemplateScope(false), - ExceptionSpecTokens(nullptr) {} + : Self(P), Method(M), ExceptionSpecTokens(nullptr) {} void ParseLexedMethodDeclarations() override; @@ -1324,11 +1345,6 @@ private: /// Method - The method declaration. Decl *Method; - /// Whether this member function had an associated template - /// scope. When true, D is a template declaration. - /// otherwise, 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 @@ -1373,18 +1389,13 @@ private: /// parsed after the corresponding top-level class is complete. struct ParsingClass { ParsingClass(Decl *TagOrTemplate, bool TopLevelClass, bool IsInterface) - : TopLevelClass(TopLevelClass), TemplateScope(false), - IsInterface(IsInterface), TagOrTemplate(TagOrTemplate) { } + : TopLevelClass(TopLevelClass), IsInterface(IsInterface), + TagOrTemplate(TagOrTemplate) {} /// Whether this is a "top-level" class, meaning that it is /// not nested within another class. bool TopLevelClass : 1; - /// Whether this class had an associated template - /// scope. When true, TagOrTemplate is a template declaration; - /// otherwise, it is a tag declaration. - bool TemplateScope : 1; - /// Whether this class is an __interface. bool IsInterface : 1; @@ -1483,6 +1494,10 @@ private: SourceRange getSourceRange() const LLVM_READONLY; }; + // In ParseCXXInlineMethods.cpp. + struct ReenterTemplateScopeRAII; + struct ReenterClassScopeRAII; + void LexTemplateFunctionForLateParsing(CachedTokens &Toks); void ParseLateTemplatedFuncDef(LateParsedTemplate &LPT); @@ -3240,7 +3255,7 @@ private: DeclaratorContext Context, const ParsedTemplateInfo &TemplateInfo, ParsingDeclRAIIObject &DiagsFromParams, SourceLocation &DeclEnd, ParsedAttributes &AccessAttrs, AccessSpecifier AS = AS_none); - bool ParseTemplateParameters(unsigned Depth, + bool ParseTemplateParameters(MultiParseScope &TemplateScopes, unsigned Depth, SmallVectorImpl &TemplateParams, SourceLocation &LAngleLoc, SourceLocation &RAngleLoc); diff --git a/clang/include/clang/Sema/Scope.h b/clang/include/clang/Sema/Scope.h index 9b8f1415a1e3..b7260f15fe1b 100644 --- a/clang/include/clang/Sema/Scope.h +++ b/clang/include/clang/Sema/Scope.h @@ -322,8 +322,21 @@ public: /// declared in. bool isDeclScope(const Decl *D) const { return DeclsInScope.count(D) != 0; } - DeclContext *getEntity() const { return Entity; } - void setEntity(DeclContext *E) { Entity = E; } + /// Get the entity corresponding to this scope. + DeclContext *getEntity() const { + return isTemplateParamScope() ? nullptr : Entity; + } + + /// Get the DeclContext in which to continue unqualified lookup after a + /// lookup in this scope. + DeclContext *getLookupEntity() const { return Entity; } + + void setEntity(DeclContext *E) { + assert(!isTemplateParamScope() && + "entity associated with template param scope"); + Entity = E; + } + void setLookupEntity(DeclContext *E) { Entity = E; } /// Determine whether any unrecoverable errors have occurred within this /// scope. Note that this may return false even if the scope contains invalid diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 88dd0d453883..19c68423e5da 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -2866,8 +2866,6 @@ public: Decl *EnumDecl, ArrayRef Elements, Scope *S, const ParsedAttributesView &Attr); - DeclContext *getContainingDC(DeclContext *DC); - /// Set the current declaration context until it gets popped. void PushDeclContext(Scope *S, DeclContext *DC); void PopDeclContext(); @@ -2877,6 +2875,11 @@ public: void EnterDeclaratorContext(Scope *S, DeclContext *DC); void ExitDeclaratorContext(Scope *S); + /// Enter a template parameter scope, after it's been associated with a particular + /// DeclContext. Causes lookup within the scope to chain through enclosing contexts + /// in the correct order. + void EnterTemplatedContext(Scope *S, DeclContext *DC); + /// Push the parameters of D, which must be a function, into scope. void ActOnReenterFunctionContext(Scope* S, Decl* D); void ActOnExitFunctionContext(); @@ -6789,7 +6792,8 @@ public: void ActOnFinishCXXNonNestedClass(); void ActOnReenterCXXMethodParameter(Scope *S, ParmVarDecl *Param); - unsigned ActOnReenterTemplateScope(Scope *S, Decl *Template); + unsigned ActOnReenterTemplateScope(Decl *Template, + llvm::function_ref EnterScope); void ActOnStartDelayedMemberDeclarations(Scope *S, Decl *Record); void ActOnStartDelayedCXXMethodDeclaration(Scope *S, Decl *Method); void ActOnDelayedCXXMethodParameter(Scope *S, Decl *Param); diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index a9cd7918da9b..3fd27757815e 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -251,7 +251,7 @@ const TemplateParameterList *Decl::getDescribedTemplateParams() const { } bool Decl::isTemplated() const { - // A declaration is dependent if it is a template or a template pattern, or + // A declaration is templated if it is a template or a template pattern, or // is within (lexcially for a friend, semantically otherwise) a dependent // context. // FIXME: Should local extern declarations be treated like friends? diff --git a/clang/lib/Parse/ParseCXXInlineMethods.cpp b/clang/lib/Parse/ParseCXXInlineMethods.cpp index 7234a656e9d1..d05332b5ac5a 100644 --- a/clang/lib/Parse/ParseCXXInlineMethods.cpp +++ b/clang/lib/Parse/ParseCXXInlineMethods.cpp @@ -133,9 +133,6 @@ NamedDecl *Parser::ParseCXXInlineMethodDef( LexedMethod* LM = new LexedMethod(this, FnD); getCurrentClass().LateParsedDeclarations.push_back(LM); - LM->TemplateScope = getCurScope()->isTemplateParamScope() || - (FnD && isa(FnD) && - cast(FnD)->isAbbreviated()); CachedTokens &Toks = LM->Toks; tok::TokenKind kind = Tok.getKind(); @@ -275,53 +272,71 @@ void Parser::LateParsedPragma::ParseLexedPragmas() { Self->ParseLexedPragma(*this); } +/// Utility to re-enter a possibly-templated scope while parsing its +/// late-parsed components. +struct Parser::ReenterTemplateScopeRAII { + Parser &P; + MultiParseScope Scopes; + TemplateParameterDepthRAII CurTemplateDepthTracker; + + ReenterTemplateScopeRAII(Parser &P, Decl *MaybeTemplated, bool Enter = true) + : P(P), Scopes(P), CurTemplateDepthTracker(P.TemplateParameterDepth) { + if (Enter) { + CurTemplateDepthTracker.addDepth( + P.ReenterTemplateScopes(Scopes, MaybeTemplated)); + } + } +}; + +/// Utility to re-enter a class scope while parsing its late-parsed components. +struct Parser::ReenterClassScopeRAII : ReenterTemplateScopeRAII { + ParsingClass &Class; + + ReenterClassScopeRAII(Parser &P, ParsingClass &Class) + : ReenterTemplateScopeRAII(P, Class.TagOrTemplate, + /*Enter=*/!Class.TopLevelClass), + Class(Class) { + // If this is the top-level class, we're still within its scope. + if (Class.TopLevelClass) + return; + + // Re-enter the class scope itself. + Scopes.Enter(Scope::ClassScope|Scope::DeclScope); + P.Actions.ActOnStartDelayedMemberDeclarations(P.getCurScope(), + Class.TagOrTemplate); + } + ~ReenterClassScopeRAII() { + if (Class.TopLevelClass) + return; + + P.Actions.ActOnFinishDelayedMemberDeclarations(P.getCurScope(), + Class.TagOrTemplate); + } +}; + /// ParseLexedMethodDeclarations - We finished parsing the member /// specification of a top (non-nested) C++ class. Now go over the /// stack of method declarations with some parts for which parsing was /// delayed (such as default arguments) and parse them. void Parser::ParseLexedMethodDeclarations(ParsingClass &Class) { - bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope; - ParseScope ClassTemplateScope(this, Scope::TemplateParamScope, - HasTemplateScope); - TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth); - if (HasTemplateScope) { - Actions.ActOnReenterTemplateScope(getCurScope(), Class.TagOrTemplate); - ++CurTemplateDepthTracker; - } + ReenterClassScopeRAII InClassScope(*this, Class); - // The current scope is still active if we're the top-level class. - // Otherwise we'll need to push and enter a new scope. - bool HasClassScope = !Class.TopLevelClass; - ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope, - HasClassScope); - if (HasClassScope) - Actions.ActOnStartDelayedMemberDeclarations(getCurScope(), - Class.TagOrTemplate); - - for (size_t i = 0; i < Class.LateParsedDeclarations.size(); ++i) { - Class.LateParsedDeclarations[i]->ParseLexedMethodDeclarations(); - } - - if (HasClassScope) - Actions.ActOnFinishDelayedMemberDeclarations(getCurScope(), - Class.TagOrTemplate); + for (LateParsedDeclaration *LateD : Class.LateParsedDeclarations) + LateD->ParseLexedMethodDeclarations(); } void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) { // If this is a member template, introduce the template parameter scope. - ParseScope TemplateScope(this, Scope::TemplateParamScope, LM.TemplateScope); - TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth); - if (LM.TemplateScope) { - Actions.ActOnReenterTemplateScope(getCurScope(), LM.Method); - ++CurTemplateDepthTracker; - } + ReenterTemplateScopeRAII InFunctionTemplateScope(*this, LM.Method); + // Start the delayed C++ method declaration Actions.ActOnStartDelayedCXXMethodDeclaration(getCurScope(), LM.Method); // Introduce the parameters into scope and parse their default // arguments. - ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope | - Scope::FunctionDeclarationScope | Scope::DeclScope); + InFunctionTemplateScope.Scopes.Enter(Scope::FunctionPrototypeScope | + Scope::FunctionDeclarationScope | + Scope::DeclScope); for (unsigned I = 0, N = LM.DefaultArgs.size(); I != N; ++I) { auto Param = cast(LM.DefaultArgs[I].Param); // Introduce the parameter into scope. @@ -475,7 +490,7 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) { LM.ExceptionSpecTokens = nullptr; } - PrototypeScope.Exit(); + InFunctionTemplateScope.Scopes.Exit(); // Finish the delayed C++ method declaration. Actions.ActOnFinishDelayedCXXMethodDeclaration(getCurScope(), LM.Method); @@ -485,30 +500,15 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) { /// (non-nested) C++ class. Now go over the stack of lexed methods that were /// collected during its parsing and parse them all. void Parser::ParseLexedMethodDefs(ParsingClass &Class) { - bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope; - ParseScope ClassTemplateScope(this, Scope::TemplateParamScope, HasTemplateScope); - TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth); - if (HasTemplateScope) { - Actions.ActOnReenterTemplateScope(getCurScope(), Class.TagOrTemplate); - ++CurTemplateDepthTracker; - } - bool HasClassScope = !Class.TopLevelClass; - ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope, - HasClassScope); + ReenterClassScopeRAII InClassScope(*this, Class); - for (size_t i = 0; i < Class.LateParsedDeclarations.size(); ++i) { - Class.LateParsedDeclarations[i]->ParseLexedMethodDefs(); - } + for (LateParsedDeclaration *D : Class.LateParsedDeclarations) + D->ParseLexedMethodDefs(); } void Parser::ParseLexedMethodDef(LexedMethod &LM) { // If this is a member template, introduce the template parameter scope. - ParseScope TemplateScope(this, Scope::TemplateParamScope, LM.TemplateScope); - TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth); - if (LM.TemplateScope) { - Actions.ActOnReenterTemplateScope(getCurScope(), LM.D); - ++CurTemplateDepthTracker; - } + ReenterTemplateScopeRAII InFunctionTemplateScope(*this, LM.D); ParenBraceBracketBalancer BalancerRAIIObj(*this); @@ -589,23 +589,7 @@ void Parser::ParseLexedMethodDef(LexedMethod &LM) { /// of a top (non-nested) C++ class. Now go over the stack of lexed data member /// initializers that were collected during its parsing and parse them all. void Parser::ParseLexedMemberInitializers(ParsingClass &Class) { - bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope; - ParseScope ClassTemplateScope(this, Scope::TemplateParamScope, - HasTemplateScope); - TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth); - if (HasTemplateScope) { - Actions.ActOnReenterTemplateScope(getCurScope(), Class.TagOrTemplate); - ++CurTemplateDepthTracker; - } - // Set or update the scope flags. - bool AlreadyHasClassScope = Class.TopLevelClass; - unsigned ScopeFlags = Scope::ClassScope|Scope::DeclScope; - ParseScope ClassScope(this, ScopeFlags, !AlreadyHasClassScope); - ParseScopeFlags ClassScopeFlags(this, ScopeFlags, AlreadyHasClassScope); - - if (!AlreadyHasClassScope) - Actions.ActOnStartDelayedMemberDeclarations(getCurScope(), - Class.TagOrTemplate); + ReenterClassScopeRAII InClassScope(*this, Class); if (!Class.LateParsedDeclarations.empty()) { // C++11 [expr.prim.general]p4: @@ -613,18 +597,14 @@ void Parser::ParseLexedMemberInitializers(ParsingClass &Class) { // (9.2) of a class X, the expression this is a prvalue of type "pointer // to X" within the optional brace-or-equal-initializer. It shall not // appear elsewhere in the member-declarator. + // FIXME: This should be done in ParseLexedMemberInitializer, not here. Sema::CXXThisScopeRAII ThisScope(Actions, Class.TagOrTemplate, Qualifiers()); - for (size_t i = 0; i < Class.LateParsedDeclarations.size(); ++i) { - Class.LateParsedDeclarations[i]->ParseLexedMemberInitializers(); - } + for (LateParsedDeclaration *D : Class.LateParsedDeclarations) + D->ParseLexedMemberInitializers(); } - if (!AlreadyHasClassScope) - Actions.ActOnFinishDelayedMemberDeclarations(getCurScope(), - Class.TagOrTemplate); - Actions.ActOnFinishDelayedMemberInitializers(Class.TagOrTemplate); } @@ -674,33 +654,10 @@ void Parser::ParseLexedMemberInitializer(LateParsedMemberInitializer &MI) { /// Wrapper class which calls ParseLexedAttribute, after setting up the /// scope appropriately. void Parser::ParseLexedAttributes(ParsingClass &Class) { - // Deal with templates - // FIXME: Test cases to make sure this does the right thing for templates. - bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope; - ParseScope ClassTemplateScope(this, Scope::TemplateParamScope, - HasTemplateScope); - if (HasTemplateScope) - Actions.ActOnReenterTemplateScope(getCurScope(), Class.TagOrTemplate); + ReenterClassScopeRAII InClassScope(*this, Class); - // Set or update the scope flags. - bool AlreadyHasClassScope = Class.TopLevelClass; - unsigned ScopeFlags = Scope::ClassScope|Scope::DeclScope; - ParseScope ClassScope(this, ScopeFlags, !AlreadyHasClassScope); - ParseScopeFlags ClassScopeFlags(this, ScopeFlags, AlreadyHasClassScope); - - // Enter the scope of nested classes - if (!AlreadyHasClassScope) - Actions.ActOnStartDelayedMemberDeclarations(getCurScope(), - Class.TagOrTemplate); - if (!Class.LateParsedDeclarations.empty()) { - for (unsigned i = 0, ni = Class.LateParsedDeclarations.size(); i < ni; ++i){ - Class.LateParsedDeclarations[i]->ParseLexedAttributes(); - } - } - - if (!AlreadyHasClassScope) - Actions.ActOnFinishDelayedMemberDeclarations(getCurScope(), - Class.TagOrTemplate); + for (LateParsedDeclaration *LateD : Class.LateParsedDeclarations) + LateD->ParseLexedAttributes(); } /// Parse all attributes in LAs, and attach them to Decl D. @@ -754,30 +711,22 @@ void Parser::ParseLexedAttribute(LateParsedAttribute &LA, if (LA.Decls.size() == 1) { // If the Decl is templatized, add template parameters to scope. - bool HasTemplateScope = EnterScope && D->isTemplateDecl(); - ParseScope TempScope(this, Scope::TemplateParamScope, HasTemplateScope); - if (HasTemplateScope) - Actions.ActOnReenterTemplateScope(Actions.CurScope, D); + ReenterTemplateScopeRAII InDeclScope(*this, D, EnterScope); // If the Decl is on a function, add function parameters to the scope. bool HasFunScope = EnterScope && D->isFunctionOrFunctionTemplate(); - ParseScope FnScope( - this, Scope::FnScope | Scope::DeclScope | Scope::CompoundStmtScope, - HasFunScope); - if (HasFunScope) + if (HasFunScope) { + InDeclScope.Scopes.Enter(Scope::FnScope | Scope::DeclScope | + Scope::CompoundStmtScope); Actions.ActOnReenterFunctionContext(Actions.CurScope, D); + } ParseGNUAttributeArgs(&LA.AttrName, LA.AttrNameLoc, Attrs, &endLoc, nullptr, SourceLocation(), ParsedAttr::AS_GNU, nullptr); - if (HasFunScope) { + if (HasFunScope) Actions.ActOnExitFunctionContext(); - FnScope.Exit(); // Pop scope, and remove Decls from IdResolver - } - if (HasTemplateScope) { - TempScope.Exit(); - } } else { // If there are multiple decls, then the decl cannot be within the // function scope. @@ -807,20 +756,10 @@ void Parser::ParseLexedAttribute(LateParsedAttribute &LA, } void Parser::ParseLexedPragmas(ParsingClass &Class) { - bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope; - ParseScope ClassTemplateScope(this, Scope::TemplateParamScope, - HasTemplateScope); - TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth); - if (HasTemplateScope) { - Actions.ActOnReenterTemplateScope(getCurScope(), Class.TagOrTemplate); - ++CurTemplateDepthTracker; - } - bool HasClassScope = !Class.TopLevelClass; - ParseScope ClassScope(this, Scope::ClassScope | Scope::DeclScope, - HasClassScope); + ReenterClassScopeRAII InClassScope(*this, Class); - for (LateParsedDeclaration *LPD : Class.LateParsedDeclarations) - LPD->ParseLexedPragmas(); + for (LateParsedDeclaration *D : Class.LateParsedDeclarations) + D->ParseLexedPragmas(); } void Parser::ParseLexedPragma(LateParsedPragma &LP) { diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index a236a82213fb..06ac545da519 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -2185,7 +2185,6 @@ void Parser::HandleMemberFunctionDeclDelays(Declarator& DeclaratorInfo, // declarations. auto LateMethod = new LateParsedMethodDeclaration(this, ThisDecl); getCurrentClass().LateParsedDeclarations.push_back(LateMethod); - LateMethod->TemplateScope = getCurScope()->isTemplateParamScope(); // Stash the exception-specification tokens in the late-pased method. LateMethod->ExceptionSpecTokens = FTI.ExceptionSpecTokens; @@ -3931,8 +3930,8 @@ void Parser::PopParsingClass(Sema::ParsingClassState state) { // after the top-level class is completely defined. Therefore, add // it to the list of nested classes within its parent. assert(getCurScope()->isClassScope() && "Nested class outside of class scope?"); - ClassStack.top()->LateParsedDeclarations.push_back(new LateParsedClass(this, Victim)); - Victim->TemplateScope = getCurScope()->getParent()->isTemplateParamScope(); + ClassStack.top()->LateParsedDeclarations.push_back( + new LateParsedClass(this, Victim)); } /// Try to parse an 'identifier' which appears within an attribute-token. diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index 48277dc85466..aa35200c33b6 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -1258,17 +1258,16 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( }; // FIXME: Consider allowing this as an extension for GCC compatibiblity. - const bool HasExplicitTemplateParams = Tok.is(tok::less); - ParseScope TemplateParamScope(this, Scope::TemplateParamScope, - /*EnteredScope=*/HasExplicitTemplateParams); - if (HasExplicitTemplateParams) { + MultiParseScope TemplateParamScope(*this); + if (Tok.is(tok::less)) { Diag(Tok, getLangOpts().CPlusPlus20 ? diag::warn_cxx17_compat_lambda_template_parameter_list : diag::ext_lambda_template_parameter_list); SmallVector TemplateParams; SourceLocation LAngleLoc, RAngleLoc; - if (ParseTemplateParameters(CurTemplateDepthTracker.getDepth(), + if (ParseTemplateParameters(TemplateParamScope, + CurTemplateDepthTracker.getDepth(), TemplateParams, LAngleLoc, RAngleLoc)) { Actions.ActOnLambdaError(LambdaBeginLoc, getCurScope()); return ExprError(); diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp index 8917986d5e2e..546a265cff85 100644 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -647,16 +647,14 @@ namespace { class FNContextRAII final { Parser &P; Sema::CXXThisScopeRAII *ThisScope; - Parser::ParseScope *TempScope; - Parser::ParseScope *FnScope; - bool HasTemplateScope = false; + Parser::MultiParseScope Scopes; bool HasFunScope = false; FNContextRAII() = delete; FNContextRAII(const FNContextRAII &) = delete; FNContextRAII &operator=(const FNContextRAII &) = delete; public: - FNContextRAII(Parser &P, Parser::DeclGroupPtrTy Ptr) : P(P) { + FNContextRAII(Parser &P, Parser::DeclGroupPtrTy Ptr) : P(P), Scopes(P) { Decl *D = *Ptr.get().begin(); NamedDecl *ND = dyn_cast(D); RecordDecl *RD = dyn_cast_or_null(D->getDeclContext()); @@ -667,29 +665,20 @@ public: ND && ND->isCXXInstanceMember()); // If the Decl is templatized, add template parameters to scope. - HasTemplateScope = D->isTemplateDecl(); - TempScope = - new Parser::ParseScope(&P, Scope::TemplateParamScope, HasTemplateScope); - if (HasTemplateScope) - Actions.ActOnReenterTemplateScope(Actions.getCurScope(), D); + // FIXME: Track CurTemplateDepth? + P.ReenterTemplateScopes(Scopes, D); // If the Decl is on a function, add function parameters to the scope. - HasFunScope = D->isFunctionOrFunctionTemplate(); - FnScope = new Parser::ParseScope( - &P, Scope::FnScope | Scope::DeclScope | Scope::CompoundStmtScope, - HasFunScope); - if (HasFunScope) + if (D->isFunctionOrFunctionTemplate()) { + HasFunScope = true; + Scopes.Enter(Scope::FnScope | Scope::DeclScope | + Scope::CompoundStmtScope); Actions.ActOnReenterFunctionContext(Actions.getCurScope(), D); + } } ~FNContextRAII() { - if (HasFunScope) { + if (HasFunScope) P.getActions().ActOnExitFunctionContext(); - FnScope->Exit(); // Pop scope, and remove Decls from IdResolver - } - if (HasTemplateScope) - TempScope->Exit(); - delete FnScope; - delete TempScope; delete ThisScope; } }; diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index 16aecffa494a..3ef73f579123 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -22,6 +22,16 @@ #include "llvm/Support/TimeProfiler.h" using namespace clang; +/// Re-enter a possible template scope, creating as many template parameter +/// scopes as necessary. +/// \return The number of template parameter scopes entered. +unsigned Parser::ReenterTemplateScopes(MultiParseScope &S, Decl *D) { + return Actions.ActOnReenterTemplateScope(D, [&] { + S.Enter(Scope::TemplateParamScope); + return Actions.getCurScope(); + }); +} + /// Parse a template declaration, explicit instantiation, or /// explicit specialization. Decl *Parser::ParseDeclarationStartingWithTemplate( @@ -67,8 +77,7 @@ Decl *Parser::ParseTemplateDeclarationOrSpecialization( assert(Tok.isOneOf(tok::kw_export, tok::kw_template) && "Token does not start a template declaration."); - // Enter template-parameter scope. - ParseScope TemplateParmScope(this, Scope::TemplateParamScope); + MultiParseScope TemplateParamScopes(*this); // Tell the action that names should be checked in the context of // the declaration to come. @@ -116,7 +125,8 @@ Decl *Parser::ParseTemplateDeclarationOrSpecialization( // Parse the '<' template-parameter-list '>' SourceLocation LAngleLoc, RAngleLoc; SmallVector TemplateParams; - if (ParseTemplateParameters(CurTemplateDepthTracker.getDepth(), + if (ParseTemplateParameters(TemplateParamScopes, + CurTemplateDepthTracker.getDepth(), TemplateParams, LAngleLoc, RAngleLoc)) { // Skip until the semi-colon or a '}'. SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); @@ -150,9 +160,6 @@ Decl *Parser::ParseTemplateDeclarationOrSpecialization( TemplateParams, RAngleLoc, OptionalRequiresClauseConstraintER.get())); } while (Tok.isOneOf(tok::kw_export, tok::kw_template)); - unsigned NewFlags = getCurScope()->getFlags() & ~Scope::TemplateParamScope; - ParseScopeFlags TemplateScopeFlags(this, NewFlags, isSpecialization); - // Parse the actual template declaration. if (Tok.is(tok::kw_concept)) return ParseConceptDefinition( @@ -430,8 +437,9 @@ Parser::ParseConceptDefinition(const ParsedTemplateInfo &TemplateInfo, /// /// \returns true if an error occurred, false otherwise. bool Parser::ParseTemplateParameters( - unsigned Depth, SmallVectorImpl &TemplateParams, - SourceLocation &LAngleLoc, SourceLocation &RAngleLoc) { + MultiParseScope &TemplateScopes, unsigned Depth, + SmallVectorImpl &TemplateParams, SourceLocation &LAngleLoc, + SourceLocation &RAngleLoc) { // Get the template parameter list. if (!TryConsumeToken(tok::less, LAngleLoc)) { Diag(Tok.getLocation(), diag::err_expected_less_after) << "template"; @@ -440,8 +448,11 @@ bool Parser::ParseTemplateParameters( // Try to parse the template parameter list. bool Failed = false; - if (!Tok.is(tok::greater) && !Tok.is(tok::greatergreater)) + // FIXME: Missing greatergreatergreater support. + if (!Tok.is(tok::greater) && !Tok.is(tok::greatergreater)) { + TemplateScopes.Enter(Scope::TemplateParamScope); Failed = ParseTemplateParameterList(Depth, TemplateParams); + } if (Tok.is(tok::greatergreater)) { // No diagnostic required here: a template-parameter-list can only be @@ -850,9 +861,9 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) { SmallVector TemplateParams; SourceLocation LAngleLoc, RAngleLoc; { - ParseScope TemplateParmScope(this, Scope::TemplateParamScope); - if (ParseTemplateParameters(Depth + 1, TemplateParams, LAngleLoc, - RAngleLoc)) { + MultiParseScope TemplateParmScope(*this); + if (ParseTemplateParameters(TemplateParmScope, Depth + 1, TemplateParams, + LAngleLoc, RAngleLoc)) { return nullptr; } } @@ -1630,40 +1641,22 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplate &LPT) { Sema::ContextRAII GlobalSavedContext( Actions, Actions.Context.getTranslationUnitDecl()); - SmallVector TemplateParamScopeStack; + MultiParseScope Scopes(*this); - // Get the list of DeclContexts to reenter. For inline methods, we only want - // to push the DeclContext of the outermost class. This matches the way the - // parser normally parses bodies of inline methods when the outermost class is - // complete. - struct ContainingDC { - ContainingDC(DeclContext *DC, bool ShouldPush) : Pair(DC, ShouldPush) {} - llvm::PointerIntPair Pair; - DeclContext *getDC() { return Pair.getPointer(); } - bool shouldPushDC() { return Pair.getInt(); } - }; - SmallVector DeclContextsToReenter; - DeclContext *DD = FunD; - DeclContext *NextContaining = Actions.getContainingDC(DD); - while (DD && !DD->isTranslationUnit()) { - bool ShouldPush = DD == NextContaining; - DeclContextsToReenter.push_back({DD, ShouldPush}); - if (ShouldPush) - NextContaining = Actions.getContainingDC(DD); - DD = DD->getLexicalParent(); - } + // Get the list of DeclContexts to reenter. + SmallVector DeclContextsToReenter; + for (DeclContext *DC = FunD; DC && !DC->isTranslationUnit(); + DC = DC->getLexicalParent()) + DeclContextsToReenter.push_back(DC); - // Reenter template scopes from outermost to innermost. - for (ContainingDC CDC : reverse(DeclContextsToReenter)) { - TemplateParamScopeStack.push_back( - new ParseScope(this, Scope::TemplateParamScope)); - unsigned NumParamLists = Actions.ActOnReenterTemplateScope( - getCurScope(), cast(CDC.getDC())); - CurTemplateDepthTracker.addDepth(NumParamLists); - if (CDC.shouldPushDC()) { - TemplateParamScopeStack.push_back(new ParseScope(this, Scope::DeclScope)); - Actions.PushDeclContext(Actions.getCurScope(), CDC.getDC()); - } + // Reenter scopes from outermost to innermost. + for (DeclContext *DC : reverse(DeclContextsToReenter)) { + CurTemplateDepthTracker.addDepth( + ReenterTemplateScopes(Scopes, cast(DC))); + Scopes.Enter(Scope::DeclScope); + // We'll reenter the function context itself below. + if (DC != FunD) + Actions.PushDeclContext(Actions.getCurScope(), DC); } assert(!LPT.Toks.empty() && "Empty body!"); @@ -1684,8 +1677,7 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplate &LPT) { Scope::CompoundStmtScope); // Recreate the containing function DeclContext. - Sema::ContextRAII FunctionSavedContext(Actions, - Actions.getContainingDC(FunD)); + Sema::ContextRAII FunctionSavedContext(Actions, FunD->getLexicalParent()); Actions.ActOnStartOfFunctionDef(getCurScope(), FunD); @@ -1709,13 +1701,6 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplate &LPT) { } else Actions.ActOnFinishFunctionBody(LPT.D, nullptr); } - - // Exit scopes. - FnScope.Exit(); - SmallVectorImpl::reverse_iterator I = - TemplateParamScopeStack.rbegin(); - for (; I != TemplateParamScopeStack.rend(); ++I) - delete *I; } /// Lex a delayed template function for late parsing. diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 30d2e5b9e90b..852f204ea7b1 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -1257,47 +1257,8 @@ Sema::getTemplateNameKindForDiagnostics(TemplateName Name) { return TemplateNameKindForDiagnostics::DependentTemplate; } -// Determines the context to return to after temporarily entering a -// context. This depends in an unnecessarily complicated way on the -// exact ordering of callbacks from the parser. -DeclContext *Sema::getContainingDC(DeclContext *DC) { - - // Functions defined inline within classes aren't parsed until we've - // finished parsing the top-level class, so the top-level class is - // the context we'll need to return to. - // A Lambda call operator whose parent is a class must not be treated - // as an inline member function. A Lambda can be used legally - // either as an in-class member initializer or a default argument. These - // are parsed once the class has been marked complete and so the containing - // context would be the nested class (when the lambda is defined in one); - // If the class is not complete, then the lambda is being used in an - // ill-formed fashion (such as to specify the width of a bit-field, or - // in an array-bound) - in which case we still want to return the - // lexically containing DC (which could be a nested class). - if (isa(DC) && !isLambdaCallOperator(DC)) { - DC = DC->getLexicalParent(); - - // A function not defined within a class will always return to its - // lexical context. - if (!isa(DC)) - return DC; - - // A C++ inline method/friend is parsed *after* the topmost class - // it was declared in is fully parsed ("complete"); the topmost - // class is the context we need to return to. - while (CXXRecordDecl *RD = dyn_cast(DC->getLexicalParent())) - DC = RD; - - // Return the declaration context of the topmost class the inline method is - // declared in. - return DC; - } - - return DC->getLexicalParent(); -} - void Sema::PushDeclContext(Scope *S, DeclContext *DC) { - assert(getContainingDC(DC) == CurContext && + assert(DC->getLexicalParent() == CurContext && "The next DeclContext should be lexically contained in the current one."); CurContext = DC; S->setEntity(DC); @@ -1306,7 +1267,7 @@ void Sema::PushDeclContext(Scope *S, DeclContext *DC) { void Sema::PopDeclContext() { assert(CurContext && "DeclContext imbalance!"); - CurContext = getContainingDC(CurContext); + CurContext = CurContext->getLexicalParent(); assert(CurContext && "Popped translation unit!"); } @@ -1358,6 +1319,12 @@ void Sema::EnterDeclaratorContext(Scope *S, DeclContext *DC) { CurContext = DC; S->setEntity(DC); + + if (S->getParent()->isTemplateParamScope()) { + // Also set the corresponding entities for all immediately-enclosing + // template parameter scopes. + EnterTemplatedContext(S->getParent(), DC); + } } void Sema::ExitDeclaratorContext(Scope *S) { @@ -1373,6 +1340,49 @@ void Sema::ExitDeclaratorContext(Scope *S) { // disappear. } +void Sema::EnterTemplatedContext(Scope *S, DeclContext *DC) { + assert(S->isTemplateParamScope() && + "expected to be initializing a template parameter scope"); + + // C++20 [temp.local]p7: + // In the definition of a member of a class template that appears outside + // of the class template definition, the name of a member of the class + // template hides the name of a template-parameter of any enclosing class + // templates (but not a template-parameter of the member if the member is a + // class or function template). + // C++20 [temp.local]p9: + // In the definition of a class template or in the definition of a member + // of such a template that appears outside of the template definition, for + // each non-dependent base class (13.8.2.1), if the name of the base class + // or the name of a member of the base class is the same as the name of a + // template-parameter, the base class name or member name hides the + // template-parameter name (6.4.10). + // + // This means that a template parameter scope should be searched immediately + // after searching the DeclContext for which it is a template parameter + // scope. For example, for + // template template template + // void N::A::B::f(...) + // we search V then B (and base classes) then U then A (and base + // classes) then T then N then ::. + unsigned ScopeDepth = getTemplateDepth(S); + for (; S && S->isTemplateParamScope(); S = S->getParent(), --ScopeDepth) { + DeclContext *SearchDCAfterScope = DC; + for (; DC; DC = DC->getLookupParent()) { + if (const TemplateParameterList *TPL = + cast(DC)->getDescribedTemplateParams()) { + unsigned DCDepth = TPL->getDepth() + 1; + if (DCDepth > ScopeDepth) + continue; + if (ScopeDepth == DCDepth) + SearchDCAfterScope = DC = DC->getLookupParent(); + break; + } + } + S->setLookupEntity(SearchDCAfterScope); + } +} + void Sema::ActOnReenterFunctionContext(Scope* S, Decl *D) { // We assume that the caller has already called // ActOnReenterTemplateScope so getTemplatedDecl() works. @@ -16152,7 +16162,7 @@ Decl *Sema::ActOnObjCContainerStartDefinition(Decl *IDecl) { assert(isa(IDecl) && "ActOnObjCContainerStartDefinition - Not ObjCContainerDecl"); DeclContext *OCD = cast(IDecl); - assert(getContainingDC(OCD) == CurContext && + assert(OCD->getLexicalParent() == CurContext && "The next DeclContext should be lexically contained in the current one."); CurContext = OCD; return IDecl; diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index e38ea6d2bc08..5e849a190760 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -9935,19 +9935,17 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { } } -unsigned Sema::ActOnReenterTemplateScope(Scope *S, Decl *D) { +unsigned +Sema::ActOnReenterTemplateScope(Decl *D, + llvm::function_ref EnterScope) { if (!D) return 0; + AdjustDeclIfTemplate(D); - // The order of template parameters is not important here. All names - // get added to the same scope. + // In order to get name lookup right, reenter template scopes in order from + // outermost to innermost. SmallVector ParameterLists; - - if (TemplateDecl *TD = dyn_cast(D)) - D = TD->getTemplatedDecl(); - - if (auto *PSD = dyn_cast(D)) - ParameterLists.push_back(PSD->getTemplateParameters()); + DeclContext *LookupDC = dyn_cast(D); if (DeclaratorDecl *DD = dyn_cast(D)) { for (unsigned i = 0; i < DD->getNumTemplateParameterLists(); ++i) @@ -9956,31 +9954,49 @@ unsigned Sema::ActOnReenterTemplateScope(Scope *S, Decl *D) { if (FunctionDecl *FD = dyn_cast(D)) { if (FunctionTemplateDecl *FTD = FD->getDescribedFunctionTemplate()) ParameterLists.push_back(FTD->getTemplateParameters()); - } - } + } else if (VarDecl *VD = dyn_cast(D)) { + LookupDC = VD->getDeclContext(); - if (TagDecl *TD = dyn_cast(D)) { + if (VarTemplateDecl *VTD = VD->getDescribedVarTemplate()) + ParameterLists.push_back(VTD->getTemplateParameters()); + else if (auto *PSD = dyn_cast(D)) + ParameterLists.push_back(PSD->getTemplateParameters()); + } + } else if (TagDecl *TD = dyn_cast(D)) { for (unsigned i = 0; i < TD->getNumTemplateParameterLists(); ++i) ParameterLists.push_back(TD->getTemplateParameterList(i)); if (CXXRecordDecl *RD = dyn_cast(TD)) { if (ClassTemplateDecl *CTD = RD->getDescribedClassTemplate()) ParameterLists.push_back(CTD->getTemplateParameters()); + else if (auto *PSD = dyn_cast(D)) + ParameterLists.push_back(PSD->getTemplateParameters()); } } + // FIXME: Alias declarations and concepts. unsigned Count = 0; + Scope *InnermostTemplateScope = nullptr; for (TemplateParameterList *Params : ParameterLists) { - if (Params->size() > 0) - // Ignore explicit specializations; they don't contribute to the template - // depth. - ++Count; + // Ignore explicit specializations; they don't contribute to the template + // depth. + if (Params->size() == 0) + continue; + + InnermostTemplateScope = EnterScope(); for (NamedDecl *Param : *Params) { if (Param->getDeclName()) { - S->AddDecl(Param); + InnermostTemplateScope->AddDecl(Param); IdResolver.AddDecl(Param); } } + ++Count; + } + + // Associate the new template scopes with the corresponding entities. + if (InnermostTemplateScope) { + assert(LookupDC && "no enclosing DeclContext for template lookup"); + EnterTemplatedContext(InnermostTemplateScope, LookupDC); } return Count; diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index 06a4dfa0a636..5757eaf3fac0 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -1153,73 +1153,14 @@ static bool isNamespaceOrTranslationUnitScope(Scope *S) { return false; } -// Find the next outer declaration context from this scope. This -// routine actually returns the semantic outer context, which may -// differ from the lexical context (encoded directly in the Scope -// stack) when we are parsing a member of a class template. In this -// case, the second element of the pair will be true, to indicate that -// name lookup should continue searching in this semantic context when -// it leaves the current template parameter scope. -static std::pair findOuterContext(Scope *S) { - DeclContext *DC = S->getEntity(); - DeclContext *Lexical = nullptr; - for (Scope *OuterS = S->getParent(); OuterS; - OuterS = OuterS->getParent()) { - if (OuterS->getEntity()) { - Lexical = OuterS->getEntity(); - break; - } - } - - // C++ [temp.local]p8: - // In the definition of a member of a class template that appears - // outside of the namespace containing the class template - // definition, the name of a template-parameter hides the name of - // a member of this namespace. - // - // Example: - // - // namespace N { - // class C { }; - // - // template class B { - // void f(T); - // }; - // } - // - // template void N::B::f(C) { - // C b; // C is the template parameter, not N::C - // } - // - // In this example, the lexical context we return is the - // TranslationUnit, while the semantic context is the namespace N. - if (!Lexical || !DC || !S->getParent() || - !S->getParent()->isTemplateParamScope()) - return std::make_pair(Lexical, false); - - // Find the outermost template parameter scope. - // For the example, this is the scope for the template parameters of - // template. - Scope *OutermostTemplateScope = S->getParent(); - while (OutermostTemplateScope->getParent() && - OutermostTemplateScope->getParent()->isTemplateParamScope()) - OutermostTemplateScope = OutermostTemplateScope->getParent(); - - // Find the namespace context in which the original scope occurs. In - // the example, this is namespace N. - DeclContext *Semantic = DC; - while (!Semantic->isFileContext()) - Semantic = Semantic->getParent(); - - // Find the declaration context just outside of the template - // parameter scope. This is the context in which the template is - // being lexically declaration (a namespace context). In the - // example, this is the global scope. - if (Lexical->isFileContext() && !Lexical->Equals(Semantic) && - Lexical->Encloses(Semantic)) - return std::make_pair(Semantic, true); - - return std::make_pair(Lexical, false); +/// Find the outer declaration context from this scope. This indicates the +/// context that we should search up to (exclusive) before considering the +/// parent of the specified scope. +static DeclContext *findOuterContext(Scope *S) { + for (Scope *OuterS = S->getParent(); OuterS; OuterS = OuterS->getParent()) + if (DeclContext *DC = OuterS->getLookupEntity()) + return DC; + return nullptr; } namespace { @@ -1286,13 +1227,11 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { UnqualUsingDirectiveSet UDirs(*this); bool VisitedUsingDirectives = false; bool LeftStartingScope = false; - DeclContext *OutsideOfTemplateParamDC = nullptr; // When performing a scope lookup, we want to find local extern decls. FindLocalExternScope FindLocals(R); for (; S && !isNamespaceOrTranslationUnitScope(S); S = S->getParent()) { - DeclContext *Ctx = S->getEntity(); bool SearchNamespaceScope = true; // Check whether the IdResolver has anything in this scope. for (; I != IEnd && S->isDeclScope(*I); ++I) { @@ -1324,7 +1263,8 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { if (!SearchNamespaceScope) { R.resolveKind(); if (S->isClassScope()) - if (CXXRecordDecl *Record = dyn_cast_or_null(Ctx)) + if (CXXRecordDecl *Record = + dyn_cast_or_null(S->getEntity())) R.setNamingClass(Record); return true; } @@ -1338,24 +1278,8 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { return false; } - if (!Ctx && S->isTemplateParamScope() && OutsideOfTemplateParamDC && - S->getParent() && !S->getParent()->isTemplateParamScope()) { - // We've just searched the last template parameter scope and - // found nothing, so look into the contexts between the - // lexical and semantic declaration contexts returned by - // findOuterContext(). This implements the name lookup behavior - // of C++ [temp.local]p8. - Ctx = OutsideOfTemplateParamDC; - OutsideOfTemplateParamDC = nullptr; - } - - if (Ctx) { - DeclContext *OuterCtx; - bool SearchAfterTemplateScope; - std::tie(OuterCtx, SearchAfterTemplateScope) = findOuterContext(S); - if (SearchAfterTemplateScope) - OutsideOfTemplateParamDC = OuterCtx; - + if (DeclContext *Ctx = S->getLookupEntity()) { + DeclContext *OuterCtx = findOuterContext(S); for (; Ctx && !Ctx->Equals(OuterCtx); Ctx = Ctx->getLookupParent()) { // We do not directly look into transparent contexts, since // those entities will be found in the nearest enclosing @@ -1480,25 +1404,9 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { return true; } - DeclContext *Ctx = S->getEntity(); - if (!Ctx && S->isTemplateParamScope() && OutsideOfTemplateParamDC && - S->getParent() && !S->getParent()->isTemplateParamScope()) { - // We've just searched the last template parameter scope and - // found nothing, so look into the contexts between the - // lexical and semantic declaration contexts returned by - // findOuterContext(). This implements the name lookup behavior - // of C++ [temp.local]p8. - Ctx = OutsideOfTemplateParamDC; - OutsideOfTemplateParamDC = nullptr; - } - + DeclContext *Ctx = S->getLookupEntity(); if (Ctx) { - DeclContext *OuterCtx; - bool SearchAfterTemplateScope; - std::tie(OuterCtx, SearchAfterTemplateScope) = findOuterContext(S); - if (SearchAfterTemplateScope) - OutsideOfTemplateParamDC = OuterCtx; - + DeclContext *OuterCtx = findOuterContext(S); for (; Ctx && !Ctx->Equals(OuterCtx); Ctx = Ctx->getLookupParent()) { // We do not directly look into transparent contexts, since // those entities will be found in the nearest enclosing @@ -3995,14 +3903,12 @@ private: } } - // FIXME: C++ [temp.local]p8 - DeclContext *Entity = nullptr; - if (S->getEntity()) { + DeclContext *Entity = S->getLookupEntity(); + if (Entity) { // Look into this scope's declaration context, along with any of its // parent lookup contexts (e.g., enclosing classes), up to the point // where we hit the context stored in the next outer scope. - Entity = S->getEntity(); - DeclContext *OuterCtx = findOuterContext(S).first; // FIXME + DeclContext *OuterCtx = findOuterContext(S); for (DeclContext *Ctx = Entity; Ctx && !Ctx->Equals(OuterCtx); Ctx = Ctx->getLookupParent()) { diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 72bd35bea0c6..021fcd0f053a 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -51,8 +51,7 @@ unsigned Sema::getTemplateDepth(Scope *S) const { // Each template parameter scope represents one level of template parameter // depth. - for (Scope *TempParamScope = S->getTemplateParamParent(); - TempParamScope && !Depth; + for (Scope *TempParamScope = S->getTemplateParamParent(); TempParamScope; TempParamScope = TempParamScope->getParent()->getTemplateParamParent()) { ++Depth; } diff --git a/clang/test/CXX/drs/dr4xx.cpp b/clang/test/CXX/drs/dr4xx.cpp index 2c762237037d..ff90ee82d4d4 100644 --- a/clang/test/CXX/drs/dr4xx.cpp +++ b/clang/test/CXX/drs/dr4xx.cpp @@ -690,7 +690,7 @@ namespace dr457 { // dr457: yes }; } -namespace dr458 { // dr458: no +namespace dr458 { // dr458: 11 struct A { int T; int f(); @@ -706,9 +706,9 @@ namespace dr458 { // dr458: no int A::f() { return T; } - template + template // expected-note {{declared here}} int A::g() { - return T; // FIXME: this is invalid, it finds the template parameter + return T; // expected-error {{'T' does not refer to a value}} } template @@ -719,9 +719,9 @@ namespace dr458 { // dr458: no int B::g() { return T; } - template template + template template // expected-note {{declared here}} int B::h() { - return T; // FIXME: this is invalid, it finds the template parameter + return T; // expected-error {{'T' does not refer to a value}} } } diff --git a/clang/test/CXX/temp/temp.res/temp.local/p8.cpp b/clang/test/CXX/temp/temp.res/temp.local/p8.cpp index fecfed06f109..6b2071eb12ce 100644 --- a/clang/test/CXX/temp/temp.res/temp.local/p8.cpp +++ b/clang/test/CXX/temp/temp.res/temp.local/p8.cpp @@ -1,5 +1,4 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s -// expected-no-diagnostics namespace N { enum { C }; @@ -52,3 +51,104 @@ void N::Y::f(D) { D d; } +// Ensure we properly interleave the searches within classes and template parameter lists. +namespace SearchClassBetweenTemplateParameterLists { + int AA, BB; // none of the below lookups should ever consider these + + struct Base { + using AA = void; + using BB = void; + }; + struct BaseT : Base { + using T = void; + }; + struct BaseU : Base { + using U = void; + }; + + template struct A { + using AA = void; + template struct B { + using BB = void; + void f(U); + void g(U); + void h(T); + void i(T); + template void j(V); + template void k(U); + + // OK: these find the template parameter not the member. + template void l(AA x) { AA aa; } + template void m(BB x) { BB bb; } + + struct C : Base { + // All OK; these find the template parameters. + template void f(T x) { T t; } + template void g(U x) { U u; } + template void h(AA x) { AA aa; } + template void i(BB x) { BB bb; } + }; + + struct CT : BaseT { + template void f(T x) { // expected-error {{void}} + T t; // expected-error {{incomplete}} + } + template void g(U x) { U u; } + template void h(AA x) { AA aa; } + template void i(BB x) { BB bb; } + }; + + struct CU : BaseU { + template void f(T x) { T t; } + template void g(U x) { // expected-error {{void}} + U u; // expected-error {{incomplete}} + } + template void h(AA x) { AA aa; } + template void i(BB x) { BB bb; } + }; + }; + }; + + // Search order for the below is: + // 1) template parameter scope of the function itself (if any) + // 2) class of which function is a member + // 3) template parameter scope of inner class + // 4) class of which class is a member + // 5) template parameter scope of outer class + + // OK, 'AA' found in (3) + template template + void A::B::f(AA) { + AA aa; + } + + // error, 'BB' found in (2) + template template + void A::B::g(BB) { // expected-error {{does not match}} + BB bb; // expected-error {{incomplete type}} + } + + // error, 'AA' found in (4) + template template + void A::B::h(AA) { // expected-error {{does not match}} + AA aa; // expected-error {{incomplete type}} + } + + // error, 'BB' found in (2) + template template + void A::B::i(BB) { // expected-error {{does not match}} + BB bb; // expected-error {{incomplete type}} + } + + // OK, 'BB' found in (1) + template template template + void A::B::j(BB) { + BB bb; + } + + // error, 'BB' found in (2) + template template template + void A::B::k(V) { // expected-error {{does not match}} + BB bb; // expected-error {{incomplete type}} + } +} diff --git a/clang/test/SemaCXX/lambda-expressions.cpp b/clang/test/SemaCXX/lambda-expressions.cpp index 0f4edc4d1f34..3240d5351fc5 100644 --- a/clang/test/SemaCXX/lambda-expressions.cpp +++ b/clang/test/SemaCXX/lambda-expressions.cpp @@ -601,16 +601,24 @@ namespace ConversionOperatorDoesNotHaveDeducedReturnType { #if __cplusplus > 201402L friend constexpr auto T::operator()(int) const; friend constexpr T::operator ExpectedTypeT() const noexcept; + + template + friend constexpr void U::operator()(T&) const; + // FIXME: This should not match; the return type is specified as behaving + // "as if it were a decltype-specifier denoting the return type of + // [operator()]", which is not equivalent to this alias template. + template + friend constexpr U::operator ExpectedTypeU() const noexcept; #else friend auto T::operator()(int) const; friend T::operator ExpectedTypeT() const; -#endif - // FIXME: The first of these should match. The second should not. template - friend void U::operator()(T&) const; // expected-error {{does not match}} + friend void U::operator()(T&) const; + // FIXME: This should not match, as above. template - friend U::operator ExpectedTypeU() const; // expected-error {{does not match}} + friend U::operator ExpectedTypeU() const; +#endif private: int n; diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html index 97879c2e64c7..65f196ad59d0 100755 --- a/clang/www/cxx_dr_status.html +++ b/clang/www/cxx_dr_status.html @@ -2789,7 +2789,7 @@ of class templates 458 C++11 Hiding of member template parameters by other members - No + Clang 11 459