summaryrefslogtreecommitdiffstats
path: root/lib/Parse
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2017-01-19 21:00:13 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2017-01-19 21:00:13 +0000
commita669043d2b89421b00d32aa819cb4e93e23560d6 (patch)
tree774828ed8bbb439941ecd8bb54f8c3496aca0303 /lib/Parse
parent103c86b73b9b22adf7932a7e67ba645e38800c0d (diff)
PR13403 (+duplicates): implement C++ DR1310 (http://wg21.link/cwg1310).
Under this defect resolution, the injected-class-name of a class or class template cannot be used except in very limited circumstances (when declaring a constructor, in a nested-name-specifier, in a base-specifier, or in an elaborated-type-specifier). This is apparently done to make parsing easier, but it's a pain for us since we don't know whether a template-id using the injected-class-name is valid at the point when we annotate it (we don't yet know whether the template-id will become part of an elaborated-type-specifier). As a tentative resolution to a perceived language defect, mem-initializer-ids are added to the list of exceptions here (they generally follow the same rules as base-specifiers). When the reference to the injected-class-name uses the 'typename' or 'template' keywords, we permit it to be used to name a type or template as an extension; other compilers also accept some cases in this area. There are also a couple of corner cases with dependent template names that we do not yet diagnose, but which will also get this treatment. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@292518 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Parse')
-rw-r--r--lib/Parse/ParseDecl.cpp69
-rw-r--r--lib/Parse/ParseExprCXX.cpp2
-rw-r--r--lib/Parse/ParseTemplate.cpp13
-rw-r--r--lib/Parse/Parser.cpp1
4 files changed, 28 insertions, 57 deletions
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 2d32087801..255f27dbfb 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -2824,44 +2824,23 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
->Kind == TNK_Type_template) {
// We have a qualified template-id, e.g., N::A<int>
- // C++ [class.qual]p2:
- // In a lookup in which the constructor is an acceptable lookup
- // result and the nested-name-specifier nominates a class C:
+ // If this would be a valid constructor declaration with template
+ // arguments, we will reject the attempt to form an invalid type-id
+ // referring to the injected-class-name when we annotate the token,
+ // per C++ [class.qual]p2.
//
- // - if the name specified after the
- // nested-name-specifier, when looked up in C, is the
- // injected-class-name of C (Clause 9), or
- //
- // - if the name specified after the nested-name-specifier
- // is the same as the identifier or the
- // simple-template-id's template-name in the last
- // component of the nested-name-specifier,
- //
- // the name is instead considered to name the constructor of
- // class C.
- //
- // Thus, if the template-name is actually the constructor
- // name, then the code is ill-formed; this interpretation is
- // reinforced by the NAD status of core issue 635.
+ // To improve diagnostics for this case, parse the declaration as a
+ // constructor (and reject the extra template arguments later).
TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Next);
if ((DSContext == DSC_top_level || DSContext == DSC_class) &&
TemplateId->Name &&
- Actions.isCurrentClassName(*TemplateId->Name, getCurScope(), &SS)) {
- if (isConstructorDeclarator(/*Unqualified*/false)) {
- // The user meant this to be an out-of-line constructor
- // definition, but template arguments are not allowed
- // there. Just allow this as a constructor; we'll
- // complain about it later.
- goto DoneWithDeclSpec;
- }
-
- // The user meant this to name a type, but it actually names
- // a constructor with some extraneous template
- // arguments. Complain, then parse it as a type as the user
- // intended.
- Diag(TemplateId->TemplateNameLoc,
- diag::err_out_of_line_template_id_type_names_constructor)
- << TemplateId->Name << 0 /* template name */;
+ Actions.isCurrentClassName(*TemplateId->Name, getCurScope(), &SS) &&
+ isConstructorDeclarator(/*Unqualified*/false)) {
+ // The user meant this to be an out-of-line constructor
+ // definition, but template arguments are not allowed
+ // there. Just allow this as a constructor; we'll
+ // complain about it later.
+ goto DoneWithDeclSpec;
}
DS.getTypeSpecScope() = SS;
@@ -2892,24 +2871,14 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
if (Next.isNot(tok::identifier))
goto DoneWithDeclSpec;
- // If we're in a context where the identifier could be a class name,
- // check whether this is a constructor declaration.
+ // Check whether this is a constructor declaration. If we're in a
+ // context where the identifier could be a class name, and it has the
+ // shape of a constructor declaration, process it as one.
if ((DSContext == DSC_top_level || DSContext == DSC_class) &&
Actions.isCurrentClassName(*Next.getIdentifierInfo(), getCurScope(),
- &SS)) {
- if (isConstructorDeclarator(/*Unqualified*/false))
- goto DoneWithDeclSpec;
-
- // As noted in C++ [class.qual]p2 (cited above), when the name
- // of the class is qualified in a context where it could name
- // a constructor, its a constructor name. However, we've
- // looked at the declarator, and the user probably meant this
- // to be a type. Complain that it isn't supposed to be treated
- // as a type, then proceed to parse it as a type.
- Diag(Next.getLocation(),
- diag::err_out_of_line_template_id_type_names_constructor)
- << Next.getIdentifierInfo() << 1 /* type */;
- }
+ &SS) &&
+ isConstructorDeclarator(/*Unqualified*/ false))
+ goto DoneWithDeclSpec;
ParsedType TypeRep =
Actions.getTypeName(*Next.getIdentifierInfo(), Next.getLocation(),
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index 124266a42b..ac0c4fd65b 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -2155,7 +2155,7 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
// Constructor and destructor names.
TypeResult Type
= Actions.ActOnTemplateIdType(SS, TemplateKWLoc,
- Template, NameLoc,
+ Template, Name, NameLoc,
LAngleLoc, TemplateArgsPtr, RAngleLoc,
/*IsCtorOrDtorName=*/true);
if (Type.isInvalid())
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp
index 6a09ea7abc..6bc35e3df5 100644
--- a/lib/Parse/ParseTemplate.cpp
+++ b/lib/Parse/ParseTemplate.cpp
@@ -1000,13 +1000,13 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
// Build the annotation token.
if (TNK == TNK_Type_template && AllowTypeAnnotation) {
- TypeResult Type
- = Actions.ActOnTemplateIdType(SS, TemplateKWLoc,
- Template, TemplateNameLoc,
- LAngleLoc, TemplateArgsPtr, RAngleLoc);
+ TypeResult Type = Actions.ActOnTemplateIdType(
+ SS, TemplateKWLoc, Template, TemplateName.Identifier,
+ TemplateNameLoc, LAngleLoc, TemplateArgsPtr, RAngleLoc);
if (Type.isInvalid()) {
- // If we failed to parse the template ID but skipped ahead to a >, we're not
- // going to be able to form a token annotation. Eat the '>' if present.
+ // If we failed to parse the template ID but skipped ahead to a >, we're
+ // not going to be able to form a token annotation. Eat the '>' if
+ // present.
TryConsumeToken(tok::greater);
return true;
}
@@ -1079,6 +1079,7 @@ void Parser::AnnotateTemplateIdTokenAsType() {
= Actions.ActOnTemplateIdType(TemplateId->SS,
TemplateId->TemplateKWLoc,
TemplateId->Template,
+ TemplateId->Name,
TemplateId->TemplateNameLoc,
TemplateId->LAngleLoc,
TemplateArgsPtr,
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index 52e5194e62..2f8ee0c068 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -1701,6 +1701,7 @@ bool Parser::TryAnnotateTypeOrScopeToken() {
Ty = Actions.ActOnTypenameType(getCurScope(), TypenameLoc, SS,
TemplateId->TemplateKWLoc,
TemplateId->Template,
+ TemplateId->Name,
TemplateId->TemplateNameLoc,
TemplateId->LAngleLoc,
TemplateArgsPtr,