Skip to content

Commit dbd82f3

Browse files
authored
[clang] NNS: don't print trailing scope resolution operator in diagnostics (#130529)
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 4fee398 commit dbd82f3

Some content is hidden

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

42 files changed

+207
-188
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -161,8 +161,8 @@ related warnings within the method body.
161161
``__attribute__((model("large")))`` on non-TLS globals in x86-64 compilations.
162162
This forces the global to be considered small or large in regards to the
163163
x86-64 code model, regardless of the code model specified for the compilation.
164-
- Clang now emits a warning ``-Wreserved-init-priority`` instead of a hard error
165-
when ``__attribute__((init_priority(n)))`` is used with values of n in the
164+
- Clang now emits a warning ``-Wreserved-init-priority`` instead of a hard error
165+
when ``__attribute__((init_priority(n)))`` is used with values of n in the
166166
reserved range [0, 100]. The warning will be treated as an error by default.
167167

168168
- There is a new ``format_matches`` attribute to complement the existing
@@ -234,7 +234,8 @@ Improvements to Clang's diagnostics
234234
- Diagnostics on chained comparisons (``a < b < c``) are now an error by default. This can be disabled with
235235
``-Wno-error=parentheses``.
236236
- The ``-Wshift-bool`` warning has been added to warn about shifting a boolean. (#GH28334)
237-
237+
- Fixed diagnostics adding a trailing ``::`` when printing some source code
238+
constructs, like base classes.
238239
- The :doc:`ThreadSafetyAnalysis` now supports ``-Wthread-safety-pointer``,
239240
which enables warning on passing or returning pointers to guarded variables
240241
as function arguments or return value respectively. Note that

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">,
@@ -5556,9 +5559,10 @@ def ext_template_spec_extra_headers : ExtWarn<
55565559
def note_explicit_template_spec_does_not_need_header : Note<
55575560
"'template<>' header not required for explicitly-specialized class %0 "
55585561
"declared here">;
5559-
def err_template_qualified_declarator_no_match : Error<
5560-
"nested name specifier '%0' for declaration does not refer into a class, "
5561-
"class template or class template partial specialization">;
5562+
def err_template_qualified_declarator_no_match
5563+
: Error<"nested name specifier %0 for declaration does not refer into a "
5564+
"class, "
5565+
"class template or class template partial specialization">;
55625566
def err_specialize_member_of_template : Error<
55635567
"cannot specialize %select{|(with 'template<>') }0a member of an "
55645568
"unspecialized template">;
@@ -5858,13 +5862,13 @@ def note_typename_member_refers_here : Note<
58585862
"referenced member %0 is declared here">;
58595863
def note_typename_refers_here : Note<
58605864
"referenced %0 is declared here">;
5861-
def err_typename_missing : Error<
5862-
"missing 'typename' prior to dependent type name '%0%1'">;
5863-
def err_typename_missing_template : Error<
5864-
"missing 'typename' prior to dependent type template name '%0%1'">;
5865-
def ext_typename_missing : ExtWarn<
5866-
"missing 'typename' prior to dependent type name '%0%1'">,
5867-
InGroup<DiagGroup<"typename-missing">>;
5865+
def err_typename_missing
5866+
: Error<"missing 'typename' prior to dependent type name %0">;
5867+
def err_typename_missing_template
5868+
: Error<"missing 'typename' prior to dependent type template name %0">;
5869+
def ext_typename_missing
5870+
: ExtWarn<"missing 'typename' prior to dependent type name %0">,
5871+
InGroup<DiagGroup<"typename-missing">>;
58685872
def ext_typename_outside_of_template : ExtWarn<
58695873
"'typename' occurs outside of a template">, InGroup<CXX11>;
58705874
def warn_cxx98_compat_typename_outside_of_template : Warning<
@@ -5878,9 +5882,10 @@ def note_using_value_decl_missing_typename : Note<
58785882
def warn_cxx17_compat_implicit_typename : Warning<"use of implicit 'typename' is "
58795883
"incompatible with C++ standards before C++20">, InGroup<CXX20Compat>,
58805884
DefaultIgnore;
5881-
def ext_implicit_typename : ExtWarn<"missing 'typename' prior to dependent "
5882-
"type name %0%1; implicit 'typename' is a C++20 extension">,
5883-
InGroup<CXX20>;
5885+
def ext_implicit_typename
5886+
: ExtWarn<"missing 'typename' prior to dependent "
5887+
"type name %0; implicit 'typename' is a C++20 extension">,
5888+
InGroup<CXX20>;
58845889

58855890
def err_template_kw_refers_to_non_template : Error<
58865891
"%0%select{| following the 'template' keyword}1 "
@@ -5890,12 +5895,13 @@ def note_template_kw_refers_to_non_template : Note<
58905895
def err_template_kw_refers_to_dependent_non_template : Error<
58915896
"%0%select{| following the 'template' keyword}1 "
58925897
"cannot refer to a dependent template">;
5893-
def err_template_kw_refers_to_type_template : Error<
5894-
"'%0%1' is expected to be a non-type template, but instantiated to a %select{class|type alias}2 template">;
5898+
def err_template_kw_refers_to_type_template
5899+
: Error<"%0 is expected to be a non-type template, but instantiated to a "
5900+
"%select{class|type alias}1 template">;
58955901
def note_referenced_type_template : Note<
58965902
"%select{class|type alias}0 template declared here">;
5897-
def err_template_kw_missing : Error<
5898-
"missing 'template' keyword prior to dependent template name '%0%1'">;
5903+
def err_template_kw_missing
5904+
: Error<"missing 'template' keyword prior to dependent template name %0">;
58995905
def ext_template_outside_of_template : ExtWarn<
59005906
"'template' keyword outside of a template">, InGroup<CXX11>;
59015907
def warn_cxx98_compat_template_outside_of_template : Warning<
@@ -7888,8 +7894,8 @@ def err_nogetter_property_incdec : Error<
78887894
"no getter method %1 for %select{increment|decrement}0 of property">;
78897895
def err_no_subobject_property_setting : Error<
78907896
"expression is not assignable">;
7891-
def err_qualified_objc_access : Error<
7892-
"%select{property|instance variable}0 access cannot be qualified with '%1'">;
7897+
def err_qualified_objc_access : Error<"%select{property|instance variable}0 "
7898+
"access cannot be qualified with %1">;
78937899

78947900
def ext_freestanding_complex : Extension<
78957901
"complex numbers are an extension in a freestanding C99 implementation">;
@@ -9839,8 +9845,8 @@ def note_non_usual_function_declared_here : Note<
98399845
// C++ literal operators
98409846
def err_literal_operator_outside_namespace : Error<
98419847
"literal operator %0 must be in a namespace or global scope">;
9842-
def err_literal_operator_id_outside_namespace : Error<
9843-
"non-namespace scope '%0' cannot have a literal operator member">;
9848+
def err_literal_operator_id_outside_namespace
9849+
: Error<"non-namespace scope %0 cannot have a literal operator member">;
98449850
def err_literal_operator_default_argument : Error<
98459851
"literal operator cannot have a default argument">;
98469852
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

@@ -3762,16 +3762,17 @@ TypeResult Sema::ActOnTemplateIdType(
37623762
// elaborated-type-specifier (7.1.5.3).
37633763
if (!LookupCtx && isDependentScopeSpecifier(SS)) {
37643764
// C++2a relaxes some of those restrictions in [temp.res]p5.
3765+
NestedNameSpecifier *NNS =
3766+
NestedNameSpecifier::Create(Context, SS.getScopeRep(), TemplateII);
37653767
if (AllowImplicitTypename == ImplicitTypenameContext::Yes) {
37663768
if (getLangOpts().CPlusPlus20)
37673769
Diag(SS.getBeginLoc(), diag::warn_cxx17_compat_implicit_typename);
37683770
else
37693771
Diag(SS.getBeginLoc(), diag::ext_implicit_typename)
3770-
<< SS.getScopeRep() << TemplateII->getName()
3772+
<< NNS
37713773
<< FixItHint::CreateInsertion(SS.getBeginLoc(), "typename ");
37723774
} else
3773-
Diag(SS.getBeginLoc(), diag::err_typename_missing_template)
3774-
<< SS.getScopeRep() << TemplateII->getName();
3775+
Diag(SS.getBeginLoc(), diag::err_typename_missing_template) << NNS;
37753776

37763777
// FIXME: This is not quite correct recovery as we don't transform SS
37773778
// 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; };

0 commit comments

Comments
 (0)