forked from OSchip/llvm-project
Revert "DR458: Search template parameter scopes in the right order."
We weren't re-entering template scopes in the right order, causing this
to break self-host with -fdelayed-template-parsing.
This reverts commit 237c2a23b6
.
This commit is contained in:
parent
2e613d2ded
commit
02fccc26cf
|
@ -1088,31 +1088,6 @@ 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);
|
||||
|
||||
|
@ -3265,7 +3240,7 @@ private:
|
|||
DeclaratorContext Context, const ParsedTemplateInfo &TemplateInfo,
|
||||
ParsingDeclRAIIObject &DiagsFromParams, SourceLocation &DeclEnd,
|
||||
ParsedAttributes &AccessAttrs, AccessSpecifier AS = AS_none);
|
||||
bool ParseTemplateParameters(MultiParseScope &TemplateScopes, unsigned Depth,
|
||||
bool ParseTemplateParameters(unsigned Depth,
|
||||
SmallVectorImpl<NamedDecl *> &TemplateParams,
|
||||
SourceLocation &LAngleLoc,
|
||||
SourceLocation &RAngleLoc);
|
||||
|
|
|
@ -322,21 +322,8 @@ public:
|
|||
/// declared in.
|
||||
bool isDeclScope(const Decl *D) const { return DeclsInScope.count(D) != 0; }
|
||||
|
||||
/// 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; }
|
||||
DeclContext *getEntity() const { return Entity; }
|
||||
void setEntity(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
|
||||
|
|
|
@ -241,7 +241,7 @@ TemplateDecl *Decl::getDescribedTemplate() const {
|
|||
}
|
||||
|
||||
bool Decl::isTemplated() const {
|
||||
// A declaration is templated if it is a template or a template pattern, or
|
||||
// A declaration is dependent 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?
|
||||
|
|
|
@ -1258,16 +1258,17 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
|
|||
};
|
||||
|
||||
// FIXME: Consider allowing this as an extension for GCC compatibiblity.
|
||||
MultiParseScope TemplateParamScope(*this);
|
||||
if (Tok.is(tok::less)) {
|
||||
const bool HasExplicitTemplateParams = Tok.is(tok::less);
|
||||
ParseScope TemplateParamScope(this, Scope::TemplateParamScope,
|
||||
/*EnteredScope=*/HasExplicitTemplateParams);
|
||||
if (HasExplicitTemplateParams) {
|
||||
Diag(Tok, getLangOpts().CPlusPlus20
|
||||
? diag::warn_cxx17_compat_lambda_template_parameter_list
|
||||
: diag::ext_lambda_template_parameter_list);
|
||||
|
||||
SmallVector<NamedDecl*, 4> TemplateParams;
|
||||
SourceLocation LAngleLoc, RAngleLoc;
|
||||
if (ParseTemplateParameters(TemplateParamScope,
|
||||
CurTemplateDepthTracker.getDepth(),
|
||||
if (ParseTemplateParameters(CurTemplateDepthTracker.getDepth(),
|
||||
TemplateParams, LAngleLoc, RAngleLoc)) {
|
||||
Actions.ActOnLambdaError(LambdaBeginLoc, getCurScope());
|
||||
return ExprError();
|
||||
|
|
|
@ -67,7 +67,8 @@ Decl *Parser::ParseTemplateDeclarationOrSpecialization(
|
|||
assert(Tok.isOneOf(tok::kw_export, tok::kw_template) &&
|
||||
"Token does not start a template declaration.");
|
||||
|
||||
MultiParseScope TemplateParamScopes(*this);
|
||||
// Enter template-parameter scope.
|
||||
ParseScope TemplateParmScope(this, Scope::TemplateParamScope);
|
||||
|
||||
// Tell the action that names should be checked in the context of
|
||||
// the declaration to come.
|
||||
|
@ -115,8 +116,7 @@ Decl *Parser::ParseTemplateDeclarationOrSpecialization(
|
|||
// Parse the '<' template-parameter-list '>'
|
||||
SourceLocation LAngleLoc, RAngleLoc;
|
||||
SmallVector<NamedDecl*, 4> TemplateParams;
|
||||
if (ParseTemplateParameters(TemplateParamScopes,
|
||||
CurTemplateDepthTracker.getDepth(),
|
||||
if (ParseTemplateParameters(CurTemplateDepthTracker.getDepth(),
|
||||
TemplateParams, LAngleLoc, RAngleLoc)) {
|
||||
// Skip until the semi-colon or a '}'.
|
||||
SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
|
||||
|
@ -150,6 +150,9 @@ 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(
|
||||
|
@ -427,9 +430,8 @@ Parser::ParseConceptDefinition(const ParsedTemplateInfo &TemplateInfo,
|
|||
///
|
||||
/// \returns true if an error occurred, false otherwise.
|
||||
bool Parser::ParseTemplateParameters(
|
||||
MultiParseScope &TemplateScopes, unsigned Depth,
|
||||
SmallVectorImpl<NamedDecl *> &TemplateParams, SourceLocation &LAngleLoc,
|
||||
SourceLocation &RAngleLoc) {
|
||||
unsigned Depth, SmallVectorImpl<NamedDecl *> &TemplateParams,
|
||||
SourceLocation &LAngleLoc, SourceLocation &RAngleLoc) {
|
||||
// Get the template parameter list.
|
||||
if (!TryConsumeToken(tok::less, LAngleLoc)) {
|
||||
Diag(Tok.getLocation(), diag::err_expected_less_after) << "template";
|
||||
|
@ -438,11 +440,8 @@ bool Parser::ParseTemplateParameters(
|
|||
|
||||
// Try to parse the template parameter list.
|
||||
bool Failed = false;
|
||||
// FIXME: Missing greatergreatergreater support.
|
||||
if (!Tok.is(tok::greater) && !Tok.is(tok::greatergreater)) {
|
||||
TemplateScopes.Enter(Scope::TemplateParamScope);
|
||||
if (!Tok.is(tok::greater) && !Tok.is(tok::greatergreater))
|
||||
Failed = ParseTemplateParameterList(Depth, TemplateParams);
|
||||
}
|
||||
|
||||
if (Tok.is(tok::greatergreater)) {
|
||||
// No diagnostic required here: a template-parameter-list can only be
|
||||
|
@ -851,9 +850,9 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) {
|
|||
SmallVector<NamedDecl*,8> TemplateParams;
|
||||
SourceLocation LAngleLoc, RAngleLoc;
|
||||
{
|
||||
MultiParseScope TemplateParmScope(*this);
|
||||
if (ParseTemplateParameters(TemplateParmScope, Depth + 1, TemplateParams,
|
||||
LAngleLoc, RAngleLoc)) {
|
||||
ParseScope TemplateParmScope(this, Scope::TemplateParamScope);
|
||||
if (ParseTemplateParameters(Depth + 1, TemplateParams, LAngleLoc,
|
||||
RAngleLoc)) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
@ -1631,7 +1630,7 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplate &LPT) {
|
|||
Sema::ContextRAII GlobalSavedContext(
|
||||
Actions, Actions.Context.getTranslationUnitDecl());
|
||||
|
||||
MultiParseScope Scopes(*this);
|
||||
SmallVector<ParseScope*, 4> TemplateParamScopeStack;
|
||||
|
||||
// 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
|
||||
|
@ -1656,12 +1655,13 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplate &LPT) {
|
|||
|
||||
// Reenter template scopes from outermost to innermost.
|
||||
for (ContainingDC CDC : reverse(DeclContextsToReenter)) {
|
||||
Scopes.Enter(Scope::TemplateParamScope);
|
||||
TemplateParamScopeStack.push_back(
|
||||
new ParseScope(this, Scope::TemplateParamScope));
|
||||
unsigned NumParamLists = Actions.ActOnReenterTemplateScope(
|
||||
getCurScope(), cast<Decl>(CDC.getDC()));
|
||||
CurTemplateDepthTracker.addDepth(NumParamLists);
|
||||
if (CDC.shouldPushDC()) {
|
||||
Scopes.Enter(Scope::DeclScope);
|
||||
TemplateParamScopeStack.push_back(new ParseScope(this, Scope::DeclScope));
|
||||
Actions.PushDeclContext(Actions.getCurScope(), CDC.getDC());
|
||||
}
|
||||
}
|
||||
|
@ -1709,6 +1709,13 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplate &LPT) {
|
|||
} else
|
||||
Actions.ActOnFinishFunctionBody(LPT.D, nullptr);
|
||||
}
|
||||
|
||||
// Exit scopes.
|
||||
FnScope.Exit();
|
||||
SmallVectorImpl<ParseScope *>::reverse_iterator I =
|
||||
TemplateParamScopeStack.rbegin();
|
||||
for (; I != TemplateParamScopeStack.rend(); ++I)
|
||||
delete *I;
|
||||
}
|
||||
|
||||
/// Lex a delayed template function for late parsing.
|
||||
|
|
|
@ -1358,50 +1358,6 @@ void Sema::EnterDeclaratorContext(Scope *S, DeclContext *DC) {
|
|||
|
||||
CurContext = DC;
|
||||
S->setEntity(DC);
|
||||
|
||||
if (!S->getParent()->isTemplateParamScope())
|
||||
return;
|
||||
|
||||
// Also set the corresponding entities for all immediately-enclosing template
|
||||
// parameter scopes.
|
||||
//
|
||||
// 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<typename T> template<typename U> template<typename V>
|
||||
// void N::A<T>::B<U>::f(...)
|
||||
// we search V then B<U> (and base classes) then U then A<T> (and base
|
||||
// classes) then T then N then ::.
|
||||
unsigned ScopeDepth = getTemplateDepth(S);
|
||||
for (Scope *OuterS = S->getParent(); OuterS && OuterS->isTemplateParamScope();
|
||||
OuterS = OuterS->getParent(), --ScopeDepth) {
|
||||
auto *SearchDCAfterScope = DC;
|
||||
for (; DC; DC = DC->getLookupParent()) {
|
||||
if (auto *TD = cast<Decl>(DC)->getDescribedTemplate()) {
|
||||
unsigned DCDepth = TD->getTemplateParameters()->getDepth() + 1;
|
||||
if (DCDepth > ScopeDepth)
|
||||
continue;
|
||||
if (ScopeDepth == DCDepth)
|
||||
SearchDCAfterScope = DC = DC->getLookupParent();
|
||||
break;
|
||||
}
|
||||
}
|
||||
OuterS->setLookupEntity(SearchDCAfterScope);
|
||||
}
|
||||
}
|
||||
|
||||
void Sema::ExitDeclaratorContext(Scope *S) {
|
||||
|
|
|
@ -1153,14 +1153,73 @@ static bool isNamespaceOrTranslationUnitScope(Scope *S) {
|
|||
return 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;
|
||||
// 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<DeclContext *, bool> 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 T> class B {
|
||||
// void f(T);
|
||||
// };
|
||||
// }
|
||||
//
|
||||
// template<class C> void N::B<C>::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<class C>.
|
||||
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);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
@ -1227,11 +1286,13 @@ 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) {
|
||||
|
@ -1263,8 +1324,7 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
|
|||
if (!SearchNamespaceScope) {
|
||||
R.resolveKind();
|
||||
if (S->isClassScope())
|
||||
if (CXXRecordDecl *Record =
|
||||
dyn_cast_or_null<CXXRecordDecl>(S->getEntity()))
|
||||
if (CXXRecordDecl *Record = dyn_cast_or_null<CXXRecordDecl>(Ctx))
|
||||
R.setNamingClass(Record);
|
||||
return true;
|
||||
}
|
||||
|
@ -1278,8 +1338,24 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (DeclContext *Ctx = S->getLookupEntity()) {
|
||||
DeclContext *OuterCtx = findOuterContext(S);
|
||||
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;
|
||||
|
||||
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
|
||||
|
@ -1404,9 +1480,25 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
|
|||
return true;
|
||||
}
|
||||
|
||||
DeclContext *Ctx = S->getLookupEntity();
|
||||
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;
|
||||
}
|
||||
|
||||
if (Ctx) {
|
||||
DeclContext *OuterCtx = findOuterContext(S);
|
||||
DeclContext *OuterCtx;
|
||||
bool SearchAfterTemplateScope;
|
||||
std::tie(OuterCtx, SearchAfterTemplateScope) = findOuterContext(S);
|
||||
if (SearchAfterTemplateScope)
|
||||
OutsideOfTemplateParamDC = OuterCtx;
|
||||
|
||||
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
|
||||
|
@ -3903,12 +3995,14 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
DeclContext *Entity = S->getLookupEntity();
|
||||
if (Entity) {
|
||||
// FIXME: C++ [temp.local]p8
|
||||
DeclContext *Entity = nullptr;
|
||||
if (S->getEntity()) {
|
||||
// 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.
|
||||
DeclContext *OuterCtx = findOuterContext(S);
|
||||
Entity = S->getEntity();
|
||||
DeclContext *OuterCtx = findOuterContext(S).first; // FIXME
|
||||
|
||||
for (DeclContext *Ctx = Entity; Ctx && !Ctx->Equals(OuterCtx);
|
||||
Ctx = Ctx->getLookupParent()) {
|
||||
|
|
|
@ -51,7 +51,8 @@ unsigned Sema::getTemplateDepth(Scope *S) const {
|
|||
|
||||
// Each template parameter scope represents one level of template parameter
|
||||
// depth.
|
||||
for (Scope *TempParamScope = S->getTemplateParamParent(); TempParamScope;
|
||||
for (Scope *TempParamScope = S->getTemplateParamParent();
|
||||
TempParamScope && !Depth;
|
||||
TempParamScope = TempParamScope->getParent()->getTemplateParamParent()) {
|
||||
++Depth;
|
||||
}
|
||||
|
|
|
@ -690,7 +690,7 @@ namespace dr457 { // dr457: yes
|
|||
};
|
||||
}
|
||||
|
||||
namespace dr458 { // dr458: 11
|
||||
namespace dr458 { // dr458: no
|
||||
struct A {
|
||||
int T;
|
||||
int f();
|
||||
|
@ -706,9 +706,9 @@ namespace dr458 { // dr458: 11
|
|||
int A::f() {
|
||||
return T;
|
||||
}
|
||||
template<typename T> // expected-note {{declared here}}
|
||||
template<typename T>
|
||||
int A::g() {
|
||||
return T; // expected-error {{'T' does not refer to a value}}
|
||||
return T; // FIXME: this is invalid, it finds the template parameter
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
|
@ -719,9 +719,9 @@ namespace dr458 { // dr458: 11
|
|||
int B<T>::g() {
|
||||
return T;
|
||||
}
|
||||
template<typename U> template<typename T> // expected-note {{declared here}}
|
||||
template<typename U> template<typename T>
|
||||
int B<U>::h() {
|
||||
return T; // expected-error {{'T' does not refer to a value}}
|
||||
return T; // FIXME: this is invalid, it finds the template parameter
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -verify %s
|
||||
// expected-no-diagnostics
|
||||
|
||||
namespace N {
|
||||
enum { C };
|
||||
|
@ -51,63 +52,3 @@ 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
|
||||
|
||||
template<typename T> struct A {
|
||||
using AA = void;
|
||||
template<typename U> struct B {
|
||||
using BB = void;
|
||||
void f(U);
|
||||
void g(U);
|
||||
void h(T);
|
||||
void i(T);
|
||||
template<typename V> void j(V);
|
||||
template<typename V> void k(U);
|
||||
};
|
||||
};
|
||||
|
||||
// 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<typename T> template<typename AA>
|
||||
void A<T>::B<AA>::f(AA) {
|
||||
AA aa;
|
||||
}
|
||||
|
||||
// error, 'BB' found in (2)
|
||||
template<typename T> template<typename BB>
|
||||
void A<T>::B<BB>::g(BB) { // expected-error {{does not match}}
|
||||
BB bb; // expected-error {{incomplete type}}
|
||||
}
|
||||
|
||||
// error, 'AA' found in (4)
|
||||
template<typename AA> template<typename U>
|
||||
void A<AA>::B<U>::h(AA) { // expected-error {{does not match}}
|
||||
AA aa; // expected-error {{incomplete type}}
|
||||
}
|
||||
|
||||
// error, 'BB' found in (2)
|
||||
template<typename BB> template<typename U>
|
||||
void A<BB>::B<U>::i(BB) { // expected-error {{does not match}}
|
||||
BB bb; // expected-error {{incomplete type}}
|
||||
}
|
||||
|
||||
// OK, 'BB' found in (1)
|
||||
template<typename T> template<typename U> template<typename BB>
|
||||
void A<T>::B<U>::j(BB) {
|
||||
BB bb;
|
||||
}
|
||||
|
||||
// error, 'BB' found in (2)
|
||||
template<typename T> template<typename BB> template<typename V>
|
||||
void A<T>::B<BB>::k(V) { // expected-error {{does not match}}
|
||||
BB bb; // expected-error {{incomplete type}}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -601,25 +601,17 @@ namespace ConversionOperatorDoesNotHaveDeducedReturnType {
|
|||
#if __cplusplus > 201402L
|
||||
friend constexpr auto T::operator()(int) const;
|
||||
friend constexpr T::operator ExpectedTypeT() const noexcept;
|
||||
|
||||
template<typename T>
|
||||
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<typename T>
|
||||
friend constexpr U::operator ExpectedTypeU<T>() const noexcept;
|
||||
#else
|
||||
friend auto T::operator()(int) const;
|
||||
friend T::operator ExpectedTypeT() const;
|
||||
|
||||
template<typename T>
|
||||
friend void U::operator()(T&) const;
|
||||
// FIXME: This should not match, as above.
|
||||
template<typename T>
|
||||
friend U::operator ExpectedTypeU<T>() const;
|
||||
#endif
|
||||
|
||||
// FIXME: The first of these should match. The second should not.
|
||||
template<typename T>
|
||||
friend void U::operator()(T&) const; // expected-error {{does not match}}
|
||||
template<typename T>
|
||||
friend U::operator ExpectedTypeU<T>() const; // expected-error {{does not match}}
|
||||
|
||||
private:
|
||||
int n;
|
||||
};
|
||||
|
|
|
@ -2789,7 +2789,7 @@ of class templates</td>
|
|||
<td><a href="https://wg21.link/cwg458">458</a></td>
|
||||
<td>C++11</td>
|
||||
<td>Hiding of member template parameters by other members</td>
|
||||
<td class="unreleased" align="center">Clang 11</td>
|
||||
<td class="none" align="center">No</td>
|
||||
</tr>
|
||||
<tr class="open" id="459">
|
||||
<td><a href="https://wg21.link/cwg459">459</a></td>
|
||||
|
@ -12307,7 +12307,7 @@ and <I>POD class</I></td>
|
|||
<td><a href="https://wg21.link/cwg2082">2082</a></td>
|
||||
<td>CD4</td>
|
||||
<td>Referring to parameters in unevaluated operands of default arguments</td>
|
||||
<td class="unreleased" align="center">Clang 11</td>
|
||||
<td class="none" align="center">Unknown</td>
|
||||
</tr>
|
||||
<tr id="2083">
|
||||
<td><a href="https://wg21.link/cwg2083">2083</a></td>
|
||||
|
@ -13891,7 +13891,7 @@ and <I>POD class</I></td>
|
|||
<td><a href="https://wg21.link/cwg2346">2346</a></td>
|
||||
<td>DRWP</td>
|
||||
<td>Local variables in default arguments</td>
|
||||
<td class="unreleased" align="center">Clang 11</td>
|
||||
<td class="none" align="center">Unknown</td>
|
||||
</tr>
|
||||
<tr id="2347">
|
||||
<td><a href="https://wg21.link/cwg2347">2347</a></td>
|
||||
|
|
Loading…
Reference in New Issue