ANSI Doc No: X3J16/93-0130 ISO Doc No: WG21/N0337 Date: September 24, 1993 Project: Programming Language C++ Ref Doc: X3J16/93-0066 Reply To: Eric J. Krohn krohn@bae.bellcore.com +1 908 699-2708 Combining Qualifiers in the Draft Syntax for C++ (Revision 1) 1. Introduction The C++ grammar in the working paper uses class-name :: qualifiers in many places. The introduction of namespaces (X3J16/93-0055 and 93-0105) has further multiplied these rules since anywhere that class-name :: is used in the grammar a similar rule using namespace-name :: must be added. This paper proposes creating a new grammar rule, nested-name-specifier, to handle qualified nested names uniformly and using that rule in the rest of the grammar. The current grammar rules relevant to nested names are shown in Appendix I. 2. Consolidation of Qualifiers Note that the token sequence class-name:: appears in the rules for qualified-type-name-specifier, nested-class-specifier. Similarly, the sequence qualified-class-specifier:: appears in the rules for new-declarator and ptr-operator. Both qualified- class-specifier and nested-class-specifier are used for two different purposes: 1. qualified-class-specifier without an immediately following :: represents the name of a nested class in simple-type- specifier, base-specifier, and mem-initializer 2. qualified-class-specifier with an immediately following :: represents a class qualifier in new-declarator, elaborated-type-specifier, and ptr-operator. 3. nested-class-specifier with an immediately following :: represents a class qualifier in qualified-id 4. nested-class-specifier without an immediately following :: is used only in qualified-class-specifier and represents whatever the qualified-class-specifier represents (either a class qualifier or a nested class name). I propose to eliminate this duplication of uses by introducing a new rule, nested-name-specifier, to represent a qualified nested name beginning with a name and ending with a ::. September 24, 1993 Page 2 X3J16/93-0130 WG21/N0337 nested-name-specifier: class-name :: nested-name-specifier(opt) namespace-name :: nested-name-specifier(opt) A simple identifier immediately preceding a :: may be a class- name, a typedef of a class-name, a namespace-name, or a namespace alias. A template-class-id immediately preceding a :: is obviously a class-name. 2.1 Definition A nested-name-specifier specifies a class if a class-name immediately preceeds the final ::. A nested-name-specifier specifies a namespace if a namespace-name immediately preceeds the final ::. 2.2 Working Paper 5.1p8 Note that the Working Paper refers to nested-class-specifier in the text, so we have to repair those references. A nested-class-specifier (f9.1) followed by :: and the name of a member of that class (f9.2), or a member of a base of that class (f10), is a qualified-id; its type is the type of the member. Possible rewording: A nested-name-specifier specifying a class (f9.1) followed by the name of a member of that class (f9.2), or a member of a base of that class (f10), is a qualified-id; its type is the type of the member. 2.3 Working Paper 5.2.4p1 If the id-expression is a qualified-id, the nested-class- specifier of the qualified-id is looked up as a type both in the class of the object expression (or the class pointed to by the pointer expression) and the context in which the entire postfix-expression occurs. If the nested-class- specifier contains a template-class-id (f14.2), its template-arguments are evaluated in the context in which the entire postfix-expression occurs. Possible rewording: If the id-expression is a qualified-id, the class specified by the nested-name-specifier of the qualified-id is looked up as a type both in the class of the object expression (or the class pointed to by the pointer expression) and the context in which the entire postfix-expression occurs. If the nested-name-specifier contains a template-class-id (f14.2), its template-arguments are evaluated in the context in which the entire postfix-expression occurs. September 24, 1993 Page 3 X3J16/93-0130 WG21/N0337 2.4 Working Paper 7.1.6p7 qualified-class-specifier is mentioned in the text thus: When a qualified-class-specifier is used, the identifier must already have been declared as a class-name. Rewording should apply this statement to enums as well. When a :: or nested-name-specifier is used with class-key, the identifier must already have been declared as a class- name. When a :: or nested-name-specifier is used with enum, the identifier must already have been declared as an enum-name. 2.5 Working Paper 8.2.3p1 In a declaration T D where D has the form qualified-class-specifier :: * cv-qualifier-seq(opt) D1 the type of the contained declarator-id is ... cv- qualifier-seq pointer to member of class class-name of type T1, where T1 is the type assigned to the contained declarator-id in the declaration T D1. Possible rewording: In a declaration T D where D has the form ::(opt) nested-name-specifier * cv-qualifier-seq(opt) D1 the type of the contained declarator-id is ... cv- qualifier-seq pointer to member of the class specified by nested-name-specifier of type T1, where T1 is the type assigned to the contained declarator-id in the declaration T D1. 2.6 Working Paper 11.5p1 When a protected member of a base class appears in a qualified-id in a friend or a member function of a derived class the nested-class-specifier must name the derived class. Possible rewording: When a protected member of a base class appears in a qualified-id in a friend or a member function of a derived class the nested-name-specifier must specify the derived class. 3. Consolidated Grammar Rules Here are the changes to use nested-name-specifier. September 24, 1993 Page 4 X3J16/93-0130 WG21/N0337 new-declarator: * cv-qualifier-seq(opt) new-declarator(opt) ::(opt) nested-name-specifier * cv-qualifier-seq(opt) new-declarator(opt) new-declarator(opt) [ expression ] qualified-id: nested-name-specifier id-expression simple-type-specifier: ::(opt) nested-name-specifier(opt) type-name char short int long signed unsigned float double void wchar_t elaborated-type-specifier: class-key ::(opt) nested-name-specifier(opt) identifier enum ::(opt) nested-name-specifier(opt) identifier qualified-type-name-specifier: DELETED qualified-class-specifier: DELETED nested-class-specifier: DELETED ptr-operator: * cv-qualifier-seq(opt) & cv-qualifier-seq(opt) ::(opt) nested-name-specifier * cv-qualifier-seq(opt) declarator-id: id-expression ~ class-name nested-name-specifier(opt) type-name namespace-alias-definition: namespace identifier = ::(opt) nested-name-specifier(opt) identifier ; using-declaration: using ::(opt) nested-name-specifier id-expression using :: id-expression using-directive: using namespace ::(opt) nested-name-specifier(opt) identifier ; With this change, the description of using-declaration must state that the nested-name-specifier must name a namespace. September 24, 1993 Page 5 X3J16/93-0130 WG21/N0337 4. Other Problems Noted The rules for id-expression and qualified-id are mutually recursive leaving ambiguous which rule gets the qualifier. Rewrite qualified-id without the recursive reference to id- expression. qualified-id: nested-name-specifier identifier nested-name-specifier operator-function-id nested-name-specifier conversion-function-id nested-name-specifier ~ class-name The grammar in the working paper makes no allowance for enum ::identifier, nor class ::identifier, though both enum :: qualifier identifier and class :: qualifier identifier are well- formed. The proposed change to elaborated-type-specifier allows both forms. The grammar fragment ::(opt) nested-name-specifier(opt) occurs so many times in the proposed grammar rules that a shorthand notation is recommended. opt-nested-name-specifier: ::(opt) nested-name-specifier(opt) Beware that opt-nested-name-specifier is not identical to (opt) nested-name-specifier(opt). Appendix II shows the final proposed grammar changes. September 24, 1993 Page 6 X3J16/93-0130 WG21/N0337 Appendix I - Original Grammar Rules These grammar rules incorporate the changes proposed in X3J16/93-0105 and 93-0107. new-declarator: * cv-qualifier-seq(opt) new-declarator(opt) qualified-class-specifier :: * cv-qualifier-seq(opt) new-declarator(opt) direct-new-declarator id-expression: identifier operator-function-id conversion-function-id ~ class-name qualified-id qualified-id: nested-class-specifier :: id-expression type-specifier: simple-type-specifier class-specifier enum-specifier elaborated-type-specifier const volatile simple-type-specifier: ::(opt) qualified-type-name-specifier char short int long signed unsigned float double void wchar_t elaborated-type-specifier: class-key identifier class-key qualified-class-specifier :: identifier enum identifier enum qualified-class-specifier :: identifier qualified-type-name-specifier: type-name class-name :: qualified-type-name-specifier qualified-class-specifier: nested-class-specifier :: nested-class-specifier nested-class-specifier: class-name class-name :: nested-class-specifier September 24, 1993 Page 7 X3J16/93-0130 WG21/N0337 ptr-operator: * cv-qualifier-seq(opt) & cv-qualifier-seq(opt) qualified-class-specifier :: * cv-qualifier-seq(opt) declarator-id: id-expression ~ class-name qualified-type-name-specifier base-specifier: qualified-class-specifier virtual access-specifier(opt) qualified-class-specifier access-specifier virtual(opt) qualified-class-specifier mem-initializer: qualified-class-specifier ( expression-list(opt) ) identifier ( expression-list(opt) ) namespace-alias-definition: namespace identifier = qualified-namespace-specifier ; namespace-definition: namespace identifier(opt) { declaration-seq(opt) } namespace-name: identifier nested-namespace-specifier: namespace-name namespace-name :: nested-namespace-specifier qualified-namespace-specifier: ::(opt) nested-namespace-specifier using-declaration: using qualified-namespace-specifier(opt) :: id-expression ; using-directive: using namespace qualified-namespace-specifier ; September 24, 1993 Page 8 X3J16/93-0130 WG21/N0337 Appendix II - Grammar Changes Proposed grammar changes showing all proposed modifications. These changes affect grammar listings in 5.1p7, 5.3.3p1, 7.1.6p3, p5, p7, 8p4, 9p1, 10p1, 12.6.2p1, and 18. nested-name-specifier: class-name :: nested-name-specifier(opt) namespace-name :: nested-name-specifier(opt) new-declarator: * cv-qualifier-seq(opt) new-declarator(opt) ::(opt) nested-name-specifier * cv-qualifier-seq(opt) new-declarator(opt) new-declarator(opt) [ expression ] id-expression: identifier operator-function-id conversion-function-id ~ class-name qualified-id qualified-id: nested-name-specifier identifier nested-name-specifier operator-function-id nested-name-specifier conversion-function-id nested-name-specifier ~ class-name type-specifier: simple-type-specifier class-specifier enum-specifier elaborated-type-specifier const volatile simple-type-specifier: opt-nested-name-specifier type-name char short int long signed unsigned float double void wchar_t elaborated-type-specifier: class-key opt-nested-name-specifier identifier enum opt-nested-name-specifier identifier qualified-type-name-specifier: DELETED qualified-class-specifier: DELETED September 24, 1993 Page 9 X3J16/93-0130 WG21/N0337 nested-class-specifier: DELETED ptr-operator: * cv-qualifier-seq(opt) & cv-qualifier-seq(opt) ::(opt) nested-name-specifier * cv-qualifier-seq(opt) declarator-id: id-expression ~ class-name nested-name-specifier(opt) type-name base-specifier: opt-nested-name-specifier class-name virtual access-specifier(opt) opt-nested-name-specifier class-name access-specifier virtual(opt) opt-nested-name-specifier class-name mem-initializer: opt-nested-name-specifier class-name ( expression-list(opt) ) identifier ( expression-list(opt) ) namespace-alias-definition: namespace identifier = opt-nested-name-specifier identifier ; using-declaration: using ::(opt) nested-name-specifier id-expression using :: id-expression using-directive: using namespace opt-nested-name-specifier namespace-name ;