Skip to content

Commit cce9f36

Browse files
committed
[clang] NNS: don't print trailing scope resolution operator
This clears up the printing of a NestedNameSpecifier so a trailing '::' is not printed, unless it refers into the global scope. This fixes a bunch of diagnostics where the trailing :: was awkward. This also prints the NNS quoted consistenty. There is a drive-by improvement to error recovery, where now we print the actual type instead of '<dependent type>'. This will clear up further uses of NNS printing in further patches.
1 parent 74ca579 commit cce9f36

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+192
-174
lines changed

clang/include/clang/AST/NestedNameSpecifier.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,8 @@ class NestedNameSpecifier : public llvm::FoldingSetNode {
223223
/// `ns::SomeTemplate<int, MyClass>` instead of
224224
/// `ns::SomeTemplate<Container::value_type, T>`.
225225
void print(raw_ostream &OS, const PrintingPolicy &Policy,
226-
bool ResolveTemplateArguments = false) const;
226+
bool ResolveTemplateArguments = false,
227+
bool PrintFinalScopeResOp = true) const;
227228

228229
void Profile(llvm::FoldingSetNodeID &ID) const {
229230
ID.AddPointer(Prefix.getOpaqueValue());

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 41 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -599,16 +599,17 @@ def err_using_typename_non_type : Error<
599599
"'typename' keyword used on a non-type">;
600600
def err_using_dependent_value_is_type : Error<
601601
"dependent using declaration resolved to type without 'typename'">;
602-
def err_using_decl_nested_name_specifier_is_not_class : Error<
603-
"using declaration in class refers into '%0', which is not a class">;
602+
def err_using_decl_nested_name_specifier_is_not_class
603+
: Error<"using declaration in class refers into %0, which is not a class">;
604604
def warn_cxx17_compat_using_decl_non_member_enumerator : Warning<
605605
"member using declaration naming non-class '%0' enumerator is "
606606
"incompatible with C++ standards before C++20">, InGroup<CXXPre20Compat>,
607607
DefaultIgnore;
608608
def err_using_decl_nested_name_specifier_is_current_class : Error<
609609
"using declaration refers to its own class">;
610-
def err_using_decl_nested_name_specifier_is_not_base_class : Error<
611-
"using declaration refers into '%0', which is not a base class of %1">;
610+
def err_using_decl_nested_name_specifier_is_not_base_class
611+
: Error<
612+
"using declaration refers into %0, which is not a base class of %1">;
612613
def err_using_decl_constructor_not_in_direct_base : Error<
613614
"%0 is not a direct base of %1, cannot inherit constructors">;
614615
def err_using_decl_can_not_refer_to_class_member : Error<
@@ -1733,8 +1734,8 @@ def err_no_matching_local_friend_suggest : Error<
17331734
"cannot define friend function %0 in a local class definition; did you mean %3?">;
17341735
def err_partial_specialization_friend : Error<
17351736
"partial specialization cannot be declared as a friend">;
1736-
def err_qualified_friend_def : Error<
1737-
"friend function definition cannot be qualified with '%0'">;
1737+
def err_qualified_friend_def
1738+
: Error<"friend function definition cannot be qualified with %0">;
17381739
def err_friend_def_in_local_class : Error<
17391740
"friend function cannot be defined in a local class">;
17401741
def err_friend_specialization_def : Error<
@@ -1743,14 +1744,16 @@ def err_friend_not_first_in_declaration : Error<
17431744
"'friend' must appear first in a non-function declaration">;
17441745
def err_using_decl_friend : Error<
17451746
"cannot befriend target of using declaration">;
1746-
def warn_template_qualified_friend_unsupported : Warning<
1747-
"dependent nested name specifier '%0' for friend class declaration is "
1748-
"not supported; turning off access control for %1">,
1749-
InGroup<UnsupportedFriend>;
1750-
def warn_template_qualified_friend_ignored : Warning<
1751-
"dependent nested name specifier '%0' for friend template declaration is "
1752-
"not supported; ignoring this friend declaration">,
1753-
InGroup<UnsupportedFriend>;
1747+
def warn_template_qualified_friend_unsupported
1748+
: Warning<
1749+
"dependent nested name specifier %0 for friend class declaration is "
1750+
"not supported; turning off access control for %1">,
1751+
InGroup<UnsupportedFriend>;
1752+
def warn_template_qualified_friend_ignored
1753+
: Warning<"dependent nested name specifier %0 for friend template "
1754+
"declaration is "
1755+
"not supported; ignoring this friend declaration">,
1756+
InGroup<UnsupportedFriend>;
17541757
def ext_friend_tag_redecl_outside_namespace : ExtWarn<
17551758
"unqualified friend declaration referring to type outside of the nearest "
17561759
"enclosing namespace is a Microsoft extension; add a nested name specifier">,
@@ -5551,9 +5554,10 @@ def ext_template_spec_extra_headers : ExtWarn<
55515554
def note_explicit_template_spec_does_not_need_header : Note<
55525555
"'template<>' header not required for explicitly-specialized class %0 "
55535556
"declared here">;
5554-
def err_template_qualified_declarator_no_match : Error<
5555-
"nested name specifier '%0' for declaration does not refer into a class, "
5556-
"class template or class template partial specialization">;
5557+
def err_template_qualified_declarator_no_match
5558+
: Error<"nested name specifier %0 for declaration does not refer into a "
5559+
"class, "
5560+
"class template or class template partial specialization">;
55575561
def err_specialize_member_of_template : Error<
55585562
"cannot specialize %select{|(with 'template<>') }0a member of an "
55595563
"unspecialized template">;
@@ -5853,13 +5857,13 @@ def note_typename_member_refers_here : Note<
58535857
"referenced member %0 is declared here">;
58545858
def note_typename_refers_here : Note<
58555859
"referenced %0 is declared here">;
5856-
def err_typename_missing : Error<
5857-
"missing 'typename' prior to dependent type name '%0%1'">;
5858-
def err_typename_missing_template : Error<
5859-
"missing 'typename' prior to dependent type template name '%0%1'">;
5860-
def ext_typename_missing : ExtWarn<
5861-
"missing 'typename' prior to dependent type name '%0%1'">,
5862-
InGroup<DiagGroup<"typename-missing">>;
5860+
def err_typename_missing
5861+
: Error<"missing 'typename' prior to dependent type name %0">;
5862+
def err_typename_missing_template
5863+
: Error<"missing 'typename' prior to dependent type template name %0">;
5864+
def ext_typename_missing
5865+
: ExtWarn<"missing 'typename' prior to dependent type name %0">,
5866+
InGroup<DiagGroup<"typename-missing">>;
58635867
def ext_typename_outside_of_template : ExtWarn<
58645868
"'typename' occurs outside of a template">, InGroup<CXX11>;
58655869
def warn_cxx98_compat_typename_outside_of_template : Warning<
@@ -5873,9 +5877,10 @@ def note_using_value_decl_missing_typename : Note<
58735877
def warn_cxx17_compat_implicit_typename : Warning<"use of implicit 'typename' is "
58745878
"incompatible with C++ standards before C++20">, InGroup<CXX20Compat>,
58755879
DefaultIgnore;
5876-
def ext_implicit_typename : ExtWarn<"missing 'typename' prior to dependent "
5877-
"type name %0%1; implicit 'typename' is a C++20 extension">,
5878-
InGroup<CXX20>;
5880+
def ext_implicit_typename
5881+
: ExtWarn<"missing 'typename' prior to dependent "
5882+
"type name %0; implicit 'typename' is a C++20 extension">,
5883+
InGroup<CXX20>;
58795884

58805885
def err_template_kw_refers_to_non_template : Error<
58815886
"%0%select{| following the 'template' keyword}1 "
@@ -5885,12 +5890,13 @@ def note_template_kw_refers_to_non_template : Note<
58855890
def err_template_kw_refers_to_dependent_non_template : Error<
58865891
"%0%select{| following the 'template' keyword}1 "
58875892
"cannot refer to a dependent template">;
5888-
def err_template_kw_refers_to_type_template : Error<
5889-
"'%0%1' is expected to be a non-type template, but instantiated to a %select{class|type alias}2 template">;
5893+
def err_template_kw_refers_to_type_template
5894+
: Error<"%0 is expected to be a non-type template, but instantiated to a "
5895+
"%select{class|type alias}1 template">;
58905896
def note_referenced_type_template : Note<
58915897
"%select{class|type alias}0 template declared here">;
5892-
def err_template_kw_missing : Error<
5893-
"missing 'template' keyword prior to dependent template name '%0%1'">;
5898+
def err_template_kw_missing
5899+
: Error<"missing 'template' keyword prior to dependent template name %0">;
58945900
def ext_template_outside_of_template : ExtWarn<
58955901
"'template' keyword outside of a template">, InGroup<CXX11>;
58965902
def warn_cxx98_compat_template_outside_of_template : Warning<
@@ -7879,8 +7885,8 @@ def err_nogetter_property_incdec : Error<
78797885
"no getter method %1 for %select{increment|decrement}0 of property">;
78807886
def err_no_subobject_property_setting : Error<
78817887
"expression is not assignable">;
7882-
def err_qualified_objc_access : Error<
7883-
"%select{property|instance variable}0 access cannot be qualified with '%1'">;
7888+
def err_qualified_objc_access : Error<"%select{property|instance variable}0 "
7889+
"access cannot be qualified with %1">;
78847890

78857891
def ext_freestanding_complex : Extension<
78867892
"complex numbers are an extension in a freestanding C99 implementation">;
@@ -9830,8 +9836,8 @@ def note_non_usual_function_declared_here : Note<
98309836
// C++ literal operators
98319837
def err_literal_operator_outside_namespace : Error<
98329838
"literal operator %0 must be in a namespace or global scope">;
9833-
def err_literal_operator_id_outside_namespace : Error<
9834-
"non-namespace scope '%0' cannot have a literal operator member">;
9839+
def err_literal_operator_id_outside_namespace
9840+
: Error<"non-namespace scope %0 cannot have a literal operator member">;
98359841
def err_literal_operator_default_argument : Error<
98369842
"literal operator cannot have a default argument">;
98379843
def err_literal_operator_bad_param_count : Error<

clang/lib/AST/ASTDiagnostic.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -461,8 +461,9 @@ void clang::FormatASTNodeDiagnosticArgument(
461461
}
462462
case DiagnosticsEngine::ak_nestednamespec: {
463463
NestedNameSpecifier *NNS = reinterpret_cast<NestedNameSpecifier*>(Val);
464-
NNS->print(OS, Context.getPrintingPolicy());
465-
NeedQuotes = false;
464+
NNS->print(OS, Context.getPrintingPolicy(),
465+
/*ResolveTemplateArguments=*/false,
466+
/*PrintFinalScopeResOp=*/false);
466467
break;
467468
}
468469
case DiagnosticsEngine::ak_declcontext: {

clang/lib/AST/NestedNameSpecifier.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,8 @@ bool NestedNameSpecifier::containsErrors() const {
248248
/// Print this nested name specifier to the given output
249249
/// stream.
250250
void NestedNameSpecifier::print(raw_ostream &OS, const PrintingPolicy &Policy,
251-
bool ResolveTemplateArguments) const {
251+
bool ResolveTemplateArguments,
252+
bool PrintFinalScopeResOp) const {
252253
if (getPrefix())
253254
getPrefix()->print(OS, Policy);
254255

@@ -269,7 +270,8 @@ void NestedNameSpecifier::print(raw_ostream &OS, const PrintingPolicy &Policy,
269270
break;
270271

271272
case Global:
272-
break;
273+
OS << "::";
274+
return;
273275

274276
case Super:
275277
OS << "__super";
@@ -331,7 +333,8 @@ void NestedNameSpecifier::print(raw_ostream &OS, const PrintingPolicy &Policy,
331333
}
332334
}
333335

334-
OS << "::";
336+
if (PrintFinalScopeResOp)
337+
OS << "::";
335338
}
336339

337340
LLVM_DUMP_METHOD void NestedNameSpecifier::dump(const LangOptions &LO) const {

clang/lib/Sema/SemaDecl.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
351351
Diag(QualifiedLoc, diag::warn_cxx17_compat_implicit_typename);
352352
else
353353
Diag(QualifiedLoc, diag::ext_implicit_typename)
354-
<< SS->getScopeRep() << II.getName()
354+
<< NestedNameSpecifier::Create(Context, SS->getScopeRep(), &II)
355355
<< FixItHint::CreateInsertion(QualifiedLoc, "typename ");
356356
}
357357

@@ -795,9 +795,9 @@ void Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II,
795795
DiagID = diag::ext_typename_missing;
796796

797797
Diag(SS->getRange().getBegin(), DiagID)
798-
<< SS->getScopeRep() << II->getName()
799-
<< SourceRange(SS->getRange().getBegin(), IILoc)
800-
<< FixItHint::CreateInsertion(SS->getRange().getBegin(), "typename ");
798+
<< NestedNameSpecifier::Create(Context, SS->getScopeRep(), II)
799+
<< SourceRange(SS->getRange().getBegin(), IILoc)
800+
<< FixItHint::CreateInsertion(SS->getRange().getBegin(), "typename ");
801801
SuggestedType = ActOnTypenameType(S, SourceLocation(),
802802
*SS, *II, IILoc).get();
803803
} else {

clang/lib/Sema/SemaExpr.cpp

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2940,6 +2940,9 @@ ExprResult Sema::BuildQualifiedDeclarationNameExpr(
29402940
}
29412941

29422942
if (const TypeDecl *TD = R.getAsSingle<TypeDecl>()) {
2943+
QualType Ty = Context.getTypeDeclType(TD);
2944+
QualType ET = getElaboratedType(ElaboratedTypeKeyword::None, SS, Ty);
2945+
29432946
// Diagnose a missing typename if this resolved unambiguously to a type in
29442947
// a dependent context. If we can recover with a type, downgrade this to
29452948
// a warning in Microsoft compatibility mode.
@@ -2948,8 +2951,7 @@ ExprResult Sema::BuildQualifiedDeclarationNameExpr(
29482951
DiagID = diag::ext_typename_missing;
29492952
SourceLocation Loc = SS.getBeginLoc();
29502953
auto D = Diag(Loc, DiagID);
2951-
D << SS.getScopeRep() << NameInfo.getName().getAsString()
2952-
<< SourceRange(Loc, NameInfo.getEndLoc());
2954+
D << ET << SourceRange(Loc, NameInfo.getEndLoc());
29532955

29542956
// Don't recover if the caller isn't expecting us to or if we're in a SFINAE
29552957
// context.
@@ -2960,11 +2962,9 @@ ExprResult Sema::BuildQualifiedDeclarationNameExpr(
29602962
D << FixItHint::CreateInsertion(Loc, "typename ");
29612963

29622964
// Recover by pretending this was an elaborated type.
2963-
QualType Ty = Context.getTypeDeclType(TD);
29642965
TypeLocBuilder TLB;
29652966
TLB.pushTypeSpec(Ty).setNameLoc(NameInfo.getLoc());
29662967

2967-
QualType ET = getElaboratedType(ElaboratedTypeKeyword::None, SS, Ty);
29682968
ElaboratedTypeLoc QTL = TLB.push<ElaboratedTypeLoc>(ET);
29692969
QTL.setElaboratedKeywordLoc(SourceLocation());
29702970
QTL.setQualifierLoc(SS.getWithLocInContext(Context));
@@ -15433,7 +15433,7 @@ ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc,
1543315433
Diag(OE->getQualifier() ? OE->getQualifierLoc().getBeginLoc()
1543415434
: OE->getNameLoc(),
1543515435
diag::err_template_kw_missing)
15436-
<< OE->getName().getAsString() << "";
15436+
<< OE->getName().getAsIdentifierInfo();
1543715437
return ExprError();
1543815438
}
1543915439
}
@@ -21025,18 +21025,24 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) {
2102521025
NamedDecl *Temp = *ULE->decls_begin();
2102621026
const bool IsTypeAliasTemplateDecl = isa<TypeAliasTemplateDecl>(Temp);
2102721027

21028-
if (NestedNameSpecifierLoc Loc = ULE->getQualifierLoc(); Loc.hasQualifier())
21029-
Diag(NameInfo.getLoc(), diag::err_template_kw_refers_to_type_template)
21030-
<< Loc.getNestedNameSpecifier() << NameInfo.getName().getAsString()
21031-
<< Loc.getSourceRange() << IsTypeAliasTemplateDecl;
21032-
else
21033-
Diag(NameInfo.getLoc(), diag::err_template_kw_refers_to_type_template)
21034-
<< "" << NameInfo.getName().getAsString() << ULE->getSourceRange()
21035-
<< IsTypeAliasTemplateDecl;
21028+
NestedNameSpecifier *NNS = ULE->getQualifierLoc().getNestedNameSpecifier();
21029+
TemplateName TN(dyn_cast<TemplateDecl>(Temp));
21030+
if (TN.isNull())
21031+
TN = Context.getAssumedTemplateName(NameInfo.getName());
21032+
TN = Context.getQualifiedTemplateName(NNS,
21033+
/*TemplateKeyword=*/true, TN);
21034+
21035+
Diag(NameInfo.getLoc(), diag::err_template_kw_refers_to_type_template)
21036+
<< TN << ULE->getSourceRange() << IsTypeAliasTemplateDecl;
2103621037
Diag(Temp->getLocation(), diag::note_referenced_type_template)
2103721038
<< IsTypeAliasTemplateDecl;
2103821039

21039-
return CreateRecoveryExpr(NameInfo.getBeginLoc(), NameInfo.getEndLoc(), {});
21040+
QualType TST =
21041+
Context.getTemplateSpecializationType(TN, ULE->template_arguments());
21042+
QualType ET =
21043+
Context.getElaboratedType(ElaboratedTypeKeyword::None, NNS, TST);
21044+
return CreateRecoveryExpr(NameInfo.getBeginLoc(), NameInfo.getEndLoc(), {},
21045+
ET);
2104021046
}
2104121047

2104221048
// Overloaded expressions.

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -363,12 +363,12 @@ bool Sema::DiagnoseUnknownTemplateName(const IdentifierInfo &II,
363363

364364
// The code is missing a 'template' keyword prior to the dependent template
365365
// name.
366-
NestedNameSpecifier *Qualifier = (NestedNameSpecifier*)SS->getScopeRep();
367-
Diag(IILoc, diag::err_template_kw_missing)
368-
<< Qualifier << II.getName()
369-
<< FixItHint::CreateInsertion(IILoc, "template ");
366+
NestedNameSpecifier *Qualifier = (NestedNameSpecifier *)SS->getScopeRep();
370367
SuggestedTemplate
371368
= TemplateTy::make(Context.getDependentTemplateName(Qualifier, &II));
369+
Diag(IILoc, diag::err_template_kw_missing)
370+
<< SuggestedTemplate.get()
371+
<< FixItHint::CreateInsertion(IILoc, "template ");
372372
SuggestedKind = TNK_Dependent_template_name;
373373
return true;
374374
}
@@ -660,7 +660,7 @@ void Sema::diagnoseExprIntendedAsTemplateName(Scope *S, ExprResult TemplateName,
660660
// was missing.
661661
if (MissingTemplateKeyword) {
662662
Diag(NameInfo.getBeginLoc(), diag::err_template_kw_missing)
663-
<< "" << NameInfo.getName().getAsString() << SourceRange(Less, Greater);
663+
<< NameInfo.getName() << SourceRange(Less, Greater);
664664
return;
665665
}
666666

@@ -3764,16 +3764,17 @@ TypeResult Sema::ActOnTemplateIdType(
37643764
// elaborated-type-specifier (7.1.5.3).
37653765
if (!LookupCtx && isDependentScopeSpecifier(SS)) {
37663766
// C++2a relaxes some of those restrictions in [temp.res]p5.
3767+
NestedNameSpecifier *NNS =
3768+
NestedNameSpecifier::Create(Context, SS.getScopeRep(), TemplateII);
37673769
if (AllowImplicitTypename == ImplicitTypenameContext::Yes) {
37683770
if (getLangOpts().CPlusPlus20)
37693771
Diag(SS.getBeginLoc(), diag::warn_cxx17_compat_implicit_typename);
37703772
else
37713773
Diag(SS.getBeginLoc(), diag::ext_implicit_typename)
3772-
<< SS.getScopeRep() << TemplateII->getName()
3774+
<< NNS
37733775
<< FixItHint::CreateInsertion(SS.getBeginLoc(), "typename ");
37743776
} else
3775-
Diag(SS.getBeginLoc(), diag::err_typename_missing_template)
3776-
<< SS.getScopeRep() << TemplateII->getName();
3777+
Diag(SS.getBeginLoc(), diag::err_typename_missing_template) << NNS;
37773778

37783779
// FIXME: This is not quite correct recovery as we don't transform SS
37793780
// into the corresponding dependent form (and we don't diagnose missing

clang/test/CXX/basic/basic.lookup/basic.lookup.qual/class.qual/p2.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ namespace InhCtor {
190190
}
191191
struct DerivedFromNS : NS::NS {
192192
// No special case unless the NNS names a class.
193-
using InhCtor::NS::NS; // expected-error {{using declaration in class refers into 'InhCtor::NS::', which is not a class}}
193+
using InhCtor::NS::NS; // expected-error {{using declaration in class refers into 'InhCtor::NS', which is not a class}}
194194

195195
};
196196

clang/test/CXX/class.access/class.access.dcl/p1.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,7 @@ namespace test4 {
331331
// expected-warning@-2 {{access declarations are deprecated; use using declarations instead}}
332332
#else
333333
// expected-error@-4 {{ISO C++11 does not allow access declarations; use using declarations instead}}
334-
// expected-error@-5 {{using declaration refers into 'Subclass::', which is not a base class of 'C'}}
334+
// expected-error@-5 {{using declaration refers into 'Subclass', which is not a base class of 'C'}}
335335
#endif
336336

337337
int bar();

clang/test/CXX/class.access/class.friend/p3-cxx0x.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class A {
3636
public:
3737
class foo {};
3838
static int y;
39-
template <typename S> friend class B<S>::ty; // expected-warning {{dependent nested name specifier 'B<S>::' for friend class declaration is not supported}}
39+
template <typename S> friend class B<S>::ty; // expected-warning {{dependent nested name specifier 'B<S>' for friend class declaration is not supported}}
4040
};
4141

4242
template<typename T> class B { typedef int ty; };

clang/test/CXX/class.access/class.friend/p6.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ struct X {
88

99
struct Y {
1010
friend void ::f1() { } // expected-error{{friend function definition cannot be qualified with '::'}}
11-
friend void X::f2() { } // expected-error{{friend function definition cannot be qualified with 'X::'}}
11+
friend void X::f2() { } // expected-error{{friend function definition cannot be qualified with 'X'}}
1212
};
1313

1414
template <typename T> struct Z {
15-
friend void T::f() {} // expected-error{{friend function definition cannot be qualified with 'T::'}}
15+
friend void T::f() {} // expected-error{{friend function definition cannot be qualified with 'T'}}
1616
};
1717

1818
void local() {
@@ -32,6 +32,6 @@ namespace N {
3232
template<typename T> struct A {
3333
friend void f3(T) {}
3434
friend void f3<T>(T) {} // expected-error{{friend function specialization cannot be defined}}
35-
friend void N::f4(T) {} // expected-error{{friend function definition cannot be qualified with 'N::'}}
36-
friend void N::f4<T>(T) {} // expected-error{{friend function definition cannot be qualified with 'N::'}}
35+
friend void N::f4(T) {} // expected-error{{friend function definition cannot be qualified with 'N'}}
36+
friend void N::f4<T>(T) {} // expected-error{{friend function definition cannot be qualified with 'N'}}
3737
};

0 commit comments

Comments
 (0)