summaryrefslogtreecommitdiff
path: root/lib/Parse/ParseDeclCXX.cpp
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2019-05-09 03:31:27 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2019-05-09 03:31:27 +0000
commitfb98e7c13da639f34f34830a4e675367e0816cb6 (patch)
tree70e025e9b4a31559d1f061e72439b5414537ad3b /lib/Parse/ParseDeclCXX.cpp
parent70cd574857c6023b8c60e325c4029a23f716c2dd (diff)
downloadclang-fb98e7c13da639f34f34830a4e675367e0816cb6.tar.gz
[c++20] Implement P0846R0: allow (ADL-only) calls to template-ids whose
template name is not visible to unqualified lookup. In order to support this without a severe degradation in our ability to diagnose typos in template names, this change significantly restructures the way we handle template-id-shaped syntax for which lookup of the template name finds nothing. Instead of eagerly diagnosing an undeclared template name, we now form a placeholder template-name representing a name that is known to not find any templates. When the parser sees such a name, it attempts to disambiguate whether we have a less-than comparison or a template-id. Any diagnostics or typo-correction for the name are delayed until its point of use. The upshot should be a small improvement of our diagostic quality overall: we now take more syntactic context into account when trying to resolve an undeclared identifier on the left hand side of a '<'. In fact, this works well enough that the backwards-compatible portion (for an undeclared identifier rather than a lookup that finds functions but no function templates) is enabled in all language modes. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@360308 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Parse/ParseDeclCXX.cpp')
-rw-r--r--lib/Parse/ParseDeclCXX.cpp97
1 files changed, 61 insertions, 36 deletions
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index c4fe23c60c..e884884163 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -597,10 +597,11 @@ bool Parser::ParseUsingDeclarator(DeclaratorContext Context,
// Parse nested-name-specifier.
IdentifierInfo *LastII = nullptr;
- ParseOptionalCXXScopeSpecifier(D.SS, nullptr, /*EnteringContext=*/false,
- /*MayBePseudoDtor=*/nullptr,
- /*IsTypename=*/false,
- /*LastII=*/&LastII);
+ if (ParseOptionalCXXScopeSpecifier(D.SS, nullptr, /*EnteringContext=*/false,
+ /*MayBePseudoDtor=*/nullptr,
+ /*IsTypename=*/false,
+ /*LastII=*/&LastII))
+ return true;
if (D.SS.isInvalid())
return true;
@@ -1111,7 +1112,8 @@ TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc,
// Parse optional nested-name-specifier
CXXScopeSpec SS;
- ParseOptionalCXXScopeSpecifier(SS, nullptr, /*EnteringContext=*/false);
+ if (ParseOptionalCXXScopeSpecifier(SS, nullptr, /*EnteringContext=*/false))
+ return true;
BaseLoc = Tok.getLocation();
@@ -1135,7 +1137,8 @@ TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc,
if (Tok.is(tok::annot_template_id)) {
TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
if (TemplateId->Kind == TNK_Type_template ||
- TemplateId->Kind == TNK_Dependent_template_name) {
+ TemplateId->Kind == TNK_Dependent_template_name ||
+ TemplateId->Kind == TNK_Undeclared_template) {
AnnotateTemplateIdTokenAsType(/*IsClassName*/true);
assert(Tok.is(tok::annot_typename) && "template-id -> type failed");
@@ -1554,6 +1557,36 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
TemplateParameterLists *TemplateParams = TemplateInfo.TemplateParams;
+ auto RecoverFromUndeclaredTemplateName = [&](IdentifierInfo *Name,
+ SourceLocation NameLoc,
+ SourceRange TemplateArgRange,
+ bool KnownUndeclared) {
+ Diag(NameLoc, diag::err_explicit_spec_non_template)
+ << (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation)
+ << TagTokKind << Name << TemplateArgRange << KnownUndeclared;
+
+ // Strip off the last template parameter list if it was empty, since
+ // we've removed its template argument list.
+ if (TemplateParams && TemplateInfo.LastParameterListWasEmpty) {
+ if (TemplateParams->size() > 1) {
+ TemplateParams->pop_back();
+ } else {
+ TemplateParams = nullptr;
+ const_cast<ParsedTemplateInfo &>(TemplateInfo).Kind =
+ ParsedTemplateInfo::NonTemplate;
+ }
+ } else if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) {
+ // Pretend this is just a forward declaration.
+ TemplateParams = nullptr;
+ const_cast<ParsedTemplateInfo &>(TemplateInfo).Kind =
+ ParsedTemplateInfo::NonTemplate;
+ const_cast<ParsedTemplateInfo &>(TemplateInfo).TemplateLoc =
+ SourceLocation();
+ const_cast<ParsedTemplateInfo &>(TemplateInfo).ExternLoc =
+ SourceLocation();
+ }
+ };
+
// Parse the (optional) class name or simple-template-id.
IdentifierInfo *Name = nullptr;
SourceLocation NameLoc;
@@ -1574,38 +1607,26 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// try to give any location information for the list.
LAngleLoc = RAngleLoc = SourceLocation();
}
-
- Diag(NameLoc, diag::err_explicit_spec_non_template)
- << (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation)
- << TagTokKind << Name << SourceRange(LAngleLoc, RAngleLoc);
-
- // Strip off the last template parameter list if it was empty, since
- // we've removed its template argument list.
- if (TemplateParams && TemplateInfo.LastParameterListWasEmpty) {
- if (TemplateParams->size() > 1) {
- TemplateParams->pop_back();
- } else {
- TemplateParams = nullptr;
- const_cast<ParsedTemplateInfo&>(TemplateInfo).Kind
- = ParsedTemplateInfo::NonTemplate;
- }
- } else if (TemplateInfo.Kind
- == ParsedTemplateInfo::ExplicitInstantiation) {
- // Pretend this is just a forward declaration.
- TemplateParams = nullptr;
- const_cast<ParsedTemplateInfo&>(TemplateInfo).Kind
- = ParsedTemplateInfo::NonTemplate;
- const_cast<ParsedTemplateInfo&>(TemplateInfo).TemplateLoc
- = SourceLocation();
- const_cast<ParsedTemplateInfo&>(TemplateInfo).ExternLoc
- = SourceLocation();
- }
+ RecoverFromUndeclaredTemplateName(
+ Name, NameLoc, SourceRange(LAngleLoc, RAngleLoc), false);
}
} else if (Tok.is(tok::annot_template_id)) {
TemplateId = takeTemplateIdAnnotation(Tok);
NameLoc = ConsumeAnnotationToken();
- if (TemplateId->Kind != TNK_Type_template &&
+ if (TemplateId->Kind == TNK_Undeclared_template) {
+ // Try to resolve the template name to a type template.
+ Actions.ActOnUndeclaredTypeTemplateName(getCurScope(), TemplateId->Template,
+ TemplateId->Kind, NameLoc, Name);
+ if (TemplateId->Kind == TNK_Undeclared_template) {
+ RecoverFromUndeclaredTemplateName(
+ Name, NameLoc,
+ SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc), true);
+ TemplateId = nullptr;
+ }
+ }
+
+ if (TemplateId && TemplateId->Kind != TNK_Type_template &&
TemplateId->Kind != TNK_Dependent_template_name) {
// The template-name in the simple-template-id refers to
// something other than a class template. Give an appropriate
@@ -1616,7 +1637,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// FIXME: Name may be null here.
Diag(TemplateId->LAngleLoc, diag::err_template_spec_syntax_non_template)
- << TemplateId->Name << static_cast<int>(TemplateId->Kind) << Range;
+ << TemplateId->Name << static_cast<int>(TemplateId->Kind) << Range;
DS.SetTypeSpecError();
SkipUntil(tok::semi, StopBeforeMatch);
@@ -3451,7 +3472,8 @@ void Parser::ParseConstructorInitializer(Decl *ConstructorDecl) {
MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
// parse '::'[opt] nested-name-specifier[opt]
CXXScopeSpec SS;
- ParseOptionalCXXScopeSpecifier(SS, nullptr, /*EnteringContext=*/false);
+ if (ParseOptionalCXXScopeSpecifier(SS, nullptr, /*EnteringContext=*/false))
+ return true;
// : identifier
IdentifierInfo *II = nullptr;
@@ -3477,11 +3499,14 @@ MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
? takeTemplateIdAnnotation(Tok)
: nullptr;
if (TemplateId && (TemplateId->Kind == TNK_Type_template ||
- TemplateId->Kind == TNK_Dependent_template_name)) {
+ TemplateId->Kind == TNK_Dependent_template_name ||
+ TemplateId->Kind == TNK_Undeclared_template)) {
AnnotateTemplateIdTokenAsType(/*IsClassName*/true);
assert(Tok.is(tok::annot_typename) && "template-id -> type failed");
TemplateTypeTy = getTypeAnnotation(Tok);
ConsumeAnnotationToken();
+ if (!TemplateTypeTy)
+ return true;
} else {
Diag(Tok, diag::err_expected_member_or_base_name);
return true;