[clang][Parse] Add parsing support for C++ attributes on using-declarations
This is a re-application ofdc67299
which was reverted inf63adf5b
because it broke the build. The issue should now be fixed. Attribution note: The original author of this patch is Erik Pilkington. I'm only trying to land it after rebasing. Differential Revision: https://reviews.llvm.org/D91630
This commit is contained in:
parent
94b0aec0f5
commit
97d234935f
|
@ -632,6 +632,20 @@ Attributes on the ``enum`` declaration do not apply to individual enumerators.
|
||||||
|
|
||||||
Query for this feature with ``__has_extension(enumerator_attributes)``.
|
Query for this feature with ``__has_extension(enumerator_attributes)``.
|
||||||
|
|
||||||
|
C++11 Attributes on using-declarations
|
||||||
|
======================================
|
||||||
|
|
||||||
|
Clang allows C++-style ``[[]]`` attributes to be written on using-declarations.
|
||||||
|
For instance:
|
||||||
|
|
||||||
|
.. code-block:: c++
|
||||||
|
|
||||||
|
[[clang::using_if_exists]] using foo::bar;
|
||||||
|
using foo::baz [[clang::using_if_exists]];
|
||||||
|
|
||||||
|
You can test for support for this extension with
|
||||||
|
``__has_extension(cxx_attributes_on_using_declarations)``.
|
||||||
|
|
||||||
'User-Specified' System Frameworks
|
'User-Specified' System Frameworks
|
||||||
==================================
|
==================================
|
||||||
|
|
||||||
|
|
|
@ -113,6 +113,9 @@ Attribute Changes in Clang
|
||||||
|
|
||||||
- ...
|
- ...
|
||||||
|
|
||||||
|
- Added support for C++11-style ``[[]]`` attributes on using-declarations, as a
|
||||||
|
clang extension.
|
||||||
|
|
||||||
Windows Support
|
Windows Support
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
|
|
|
@ -693,6 +693,9 @@ def ext_using_attribute_ns : ExtWarn<
|
||||||
def err_using_attribute_ns_conflict : Error<
|
def err_using_attribute_ns_conflict : Error<
|
||||||
"attribute with scope specifier cannot follow default scope specifier">;
|
"attribute with scope specifier cannot follow default scope specifier">;
|
||||||
def err_attributes_not_allowed : Error<"an attribute list cannot appear here">;
|
def err_attributes_not_allowed : Error<"an attribute list cannot appear here">;
|
||||||
|
def ext_cxx11_attr_placement : ExtWarn<
|
||||||
|
"ISO C++ does not allow an attribute list to appear here">,
|
||||||
|
InGroup<DiagGroup<"cxx-attribute-extension">>;
|
||||||
def err_attributes_misplaced : Error<"misplaced attributes; expected attributes here">;
|
def err_attributes_misplaced : Error<"misplaced attributes; expected attributes here">;
|
||||||
def err_l_square_l_square_not_attribute : Error<
|
def err_l_square_l_square_not_attribute : Error<
|
||||||
"C++11 only allows consecutive left square brackets when "
|
"C++11 only allows consecutive left square brackets when "
|
||||||
|
|
|
@ -3957,6 +3957,9 @@ def warn_attribute_sentinel_named_arguments : Warning<
|
||||||
def warn_attribute_sentinel_not_variadic : Warning<
|
def warn_attribute_sentinel_not_variadic : Warning<
|
||||||
"'sentinel' attribute only supported for variadic %select{functions|blocks}0">,
|
"'sentinel' attribute only supported for variadic %select{functions|blocks}0">,
|
||||||
InGroup<IgnoredAttributes>;
|
InGroup<IgnoredAttributes>;
|
||||||
|
def warn_deprecated_ignored_on_using : Warning<
|
||||||
|
"%0 currently has no effect on a using declaration">,
|
||||||
|
InGroup<IgnoredAttributes>;
|
||||||
def err_attribute_sentinel_less_than_zero : Error<
|
def err_attribute_sentinel_less_than_zero : Error<
|
||||||
"'sentinel' parameter 1 less than zero">;
|
"'sentinel' parameter 1 less than zero">;
|
||||||
def err_attribute_sentinel_not_zero_or_one : Error<
|
def err_attribute_sentinel_not_zero_or_one : Error<
|
||||||
|
|
|
@ -259,6 +259,7 @@ EXTENSION(gnu_asm, LangOpts.GNUAsm)
|
||||||
EXTENSION(gnu_asm_goto_with_outputs, LangOpts.GNUAsm)
|
EXTENSION(gnu_asm_goto_with_outputs, LangOpts.GNUAsm)
|
||||||
EXTENSION(matrix_types, LangOpts.MatrixTypes)
|
EXTENSION(matrix_types, LangOpts.MatrixTypes)
|
||||||
EXTENSION(matrix_types_scalar_division, true)
|
EXTENSION(matrix_types_scalar_division, true)
|
||||||
|
EXTENSION(cxx_attributes_on_using_declarations, LangOpts.CPlusPlus11)
|
||||||
|
|
||||||
FEATURE(cxx_abi_relative_vtable, LangOpts.CPlusPlus && LangOpts.RelativeCXXABIVTables)
|
FEATURE(cxx_abi_relative_vtable, LangOpts.CPlusPlus && LangOpts.RelativeCXXABIVTables)
|
||||||
|
|
||||||
|
|
|
@ -2635,6 +2635,10 @@ private:
|
||||||
/// locations where attributes are not allowed.
|
/// locations where attributes are not allowed.
|
||||||
void DiagnoseAndSkipCXX11Attributes();
|
void DiagnoseAndSkipCXX11Attributes();
|
||||||
|
|
||||||
|
/// Emit warnings for C++11 and C2x attributes that are in a position that
|
||||||
|
/// clang accepts as an extension.
|
||||||
|
void DiagnoseCXX11AttributeExtension(ParsedAttributesWithRange &Attrs);
|
||||||
|
|
||||||
/// Parses syntax-generic attribute arguments for attributes which are
|
/// Parses syntax-generic attribute arguments for attributes which are
|
||||||
/// known to the implementation, and adds them to the given ParsedAttributes
|
/// known to the implementation, and adds them to the given ParsedAttributes
|
||||||
/// list with the given attribute syntax. Returns the number of arguments
|
/// list with the given attribute syntax. Returns the number of arguments
|
||||||
|
@ -3061,6 +3065,7 @@ private:
|
||||||
const ParsedTemplateInfo &TemplateInfo,
|
const ParsedTemplateInfo &TemplateInfo,
|
||||||
SourceLocation UsingLoc,
|
SourceLocation UsingLoc,
|
||||||
SourceLocation &DeclEnd,
|
SourceLocation &DeclEnd,
|
||||||
|
ParsedAttributesWithRange &Attrs,
|
||||||
AccessSpecifier AS = AS_none);
|
AccessSpecifier AS = AS_none);
|
||||||
Decl *ParseAliasDeclarationAfterDeclarator(
|
Decl *ParseAliasDeclarationAfterDeclarator(
|
||||||
const ParsedTemplateInfo &TemplateInfo, SourceLocation UsingLoc,
|
const ParsedTemplateInfo &TemplateInfo, SourceLocation UsingLoc,
|
||||||
|
|
|
@ -1650,6 +1650,13 @@ void Parser::ProhibitCXX11Attributes(ParsedAttributesWithRange &Attrs,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Parser::DiagnoseCXX11AttributeExtension(ParsedAttributesWithRange &Attrs) {
|
||||||
|
for (const ParsedAttr &PA : Attrs) {
|
||||||
|
if (PA.isCXX11Attribute() || PA.isC2xAttribute())
|
||||||
|
Diag(PA.getLoc(), diag::ext_cxx11_attr_placement) << PA << PA.getRange();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Usually, `__attribute__((attrib)) class Foo {} var` means that attribute
|
// Usually, `__attribute__((attrib)) class Foo {} var` means that attribute
|
||||||
// applies to var, not the type Foo.
|
// applies to var, not the type Foo.
|
||||||
// As an exception to the rule, __declspec(align(...)) before the
|
// As an exception to the rule, __declspec(align(...)) before the
|
||||||
|
|
|
@ -497,11 +497,7 @@ Parser::ParseUsingDirectiveOrDeclaration(DeclaratorContext Context,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, it must be a using-declaration or an alias-declaration.
|
// Otherwise, it must be a using-declaration or an alias-declaration.
|
||||||
|
return ParseUsingDeclaration(Context, TemplateInfo, UsingLoc, DeclEnd, attrs,
|
||||||
// Using declarations can't have attributes.
|
|
||||||
ProhibitAttributes(attrs);
|
|
||||||
|
|
||||||
return ParseUsingDeclaration(Context, TemplateInfo, UsingLoc, DeclEnd,
|
|
||||||
AS_none);
|
AS_none);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -627,7 +623,8 @@ bool Parser::ParseUsingDeclarator(DeclaratorContext Context,
|
||||||
if (getLangOpts().CPlusPlus11 && Context == DeclaratorContext::Member &&
|
if (getLangOpts().CPlusPlus11 && Context == DeclaratorContext::Member &&
|
||||||
Tok.is(tok::identifier) &&
|
Tok.is(tok::identifier) &&
|
||||||
(NextToken().is(tok::semi) || NextToken().is(tok::comma) ||
|
(NextToken().is(tok::semi) || NextToken().is(tok::comma) ||
|
||||||
NextToken().is(tok::ellipsis)) &&
|
NextToken().is(tok::ellipsis) || NextToken().is(tok::l_square) ||
|
||||||
|
NextToken().is(tok::kw___attribute)) &&
|
||||||
D.SS.isNotEmpty() && LastII == Tok.getIdentifierInfo() &&
|
D.SS.isNotEmpty() && LastII == Tok.getIdentifierInfo() &&
|
||||||
!D.SS.getScopeRep()->getAsNamespace() &&
|
!D.SS.getScopeRep()->getAsNamespace() &&
|
||||||
!D.SS.getScopeRep()->getAsNamespaceAlias()) {
|
!D.SS.getScopeRep()->getAsNamespaceAlias()) {
|
||||||
|
@ -670,11 +667,10 @@ bool Parser::ParseUsingDeclarator(DeclaratorContext Context,
|
||||||
/// alias-declaration: C++11 [dcl.dcl]p1
|
/// alias-declaration: C++11 [dcl.dcl]p1
|
||||||
/// 'using' identifier attribute-specifier-seq[opt] = type-id ;
|
/// 'using' identifier attribute-specifier-seq[opt] = type-id ;
|
||||||
///
|
///
|
||||||
Parser::DeclGroupPtrTy
|
Parser::DeclGroupPtrTy Parser::ParseUsingDeclaration(
|
||||||
Parser::ParseUsingDeclaration(DeclaratorContext Context,
|
DeclaratorContext Context, const ParsedTemplateInfo &TemplateInfo,
|
||||||
const ParsedTemplateInfo &TemplateInfo,
|
SourceLocation UsingLoc, SourceLocation &DeclEnd,
|
||||||
SourceLocation UsingLoc, SourceLocation &DeclEnd,
|
ParsedAttributesWithRange &PrefixAttrs, AccessSpecifier AS) {
|
||||||
AccessSpecifier AS) {
|
|
||||||
// Check for misplaced attributes before the identifier in an
|
// Check for misplaced attributes before the identifier in an
|
||||||
// alias-declaration.
|
// alias-declaration.
|
||||||
ParsedAttributesWithRange MisplacedAttrs(AttrFactory);
|
ParsedAttributesWithRange MisplacedAttrs(AttrFactory);
|
||||||
|
@ -686,6 +682,17 @@ Parser::ParseUsingDeclaration(DeclaratorContext Context,
|
||||||
ParsedAttributesWithRange Attrs(AttrFactory);
|
ParsedAttributesWithRange Attrs(AttrFactory);
|
||||||
MaybeParseAttributes(PAKM_GNU | PAKM_CXX11, Attrs);
|
MaybeParseAttributes(PAKM_GNU | PAKM_CXX11, Attrs);
|
||||||
|
|
||||||
|
// If we had any misplaced attributes from earlier, this is where they
|
||||||
|
// should have been written.
|
||||||
|
if (MisplacedAttrs.Range.isValid()) {
|
||||||
|
Diag(MisplacedAttrs.Range.getBegin(), diag::err_attributes_not_allowed)
|
||||||
|
<< FixItHint::CreateInsertionFromRange(
|
||||||
|
Tok.getLocation(),
|
||||||
|
CharSourceRange::getTokenRange(MisplacedAttrs.Range))
|
||||||
|
<< FixItHint::CreateRemoval(MisplacedAttrs.Range);
|
||||||
|
Attrs.takeAllFrom(MisplacedAttrs);
|
||||||
|
}
|
||||||
|
|
||||||
// Maybe this is an alias-declaration.
|
// Maybe this is an alias-declaration.
|
||||||
if (Tok.is(tok::equal)) {
|
if (Tok.is(tok::equal)) {
|
||||||
if (InvalidDeclarator) {
|
if (InvalidDeclarator) {
|
||||||
|
@ -693,16 +700,7 @@ Parser::ParseUsingDeclaration(DeclaratorContext Context,
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we had any misplaced attributes from earlier, this is where they
|
ProhibitAttributes(PrefixAttrs);
|
||||||
// should have been written.
|
|
||||||
if (MisplacedAttrs.Range.isValid()) {
|
|
||||||
Diag(MisplacedAttrs.Range.getBegin(), diag::err_attributes_not_allowed)
|
|
||||||
<< FixItHint::CreateInsertionFromRange(
|
|
||||||
Tok.getLocation(),
|
|
||||||
CharSourceRange::getTokenRange(MisplacedAttrs.Range))
|
|
||||||
<< FixItHint::CreateRemoval(MisplacedAttrs.Range);
|
|
||||||
Attrs.takeAllFrom(MisplacedAttrs);
|
|
||||||
}
|
|
||||||
|
|
||||||
Decl *DeclFromDeclSpec = nullptr;
|
Decl *DeclFromDeclSpec = nullptr;
|
||||||
Decl *AD = ParseAliasDeclarationAfterDeclarator(
|
Decl *AD = ParseAliasDeclarationAfterDeclarator(
|
||||||
|
@ -710,10 +708,7 @@ Parser::ParseUsingDeclaration(DeclaratorContext Context,
|
||||||
return Actions.ConvertDeclToDeclGroup(AD, DeclFromDeclSpec);
|
return Actions.ConvertDeclToDeclGroup(AD, DeclFromDeclSpec);
|
||||||
}
|
}
|
||||||
|
|
||||||
// C++11 attributes are not allowed on a using-declaration, but GNU ones
|
DiagnoseCXX11AttributeExtension(PrefixAttrs);
|
||||||
// are.
|
|
||||||
ProhibitAttributes(MisplacedAttrs);
|
|
||||||
ProhibitAttributes(Attrs);
|
|
||||||
|
|
||||||
// Diagnose an attempt to declare a templated using-declaration.
|
// Diagnose an attempt to declare a templated using-declaration.
|
||||||
// In C++11, alias-declarations can be templates:
|
// In C++11, alias-declarations can be templates:
|
||||||
|
@ -731,8 +726,10 @@ Parser::ParseUsingDeclaration(DeclaratorContext Context,
|
||||||
|
|
||||||
SmallVector<Decl *, 8> DeclsInGroup;
|
SmallVector<Decl *, 8> DeclsInGroup;
|
||||||
while (true) {
|
while (true) {
|
||||||
// Parse (optional) attributes (most likely GNU strong-using extension).
|
// Parse (optional) attributes.
|
||||||
MaybeParseGNUAttributes(Attrs);
|
MaybeParseAttributes(PAKM_GNU | PAKM_CXX11, Attrs);
|
||||||
|
DiagnoseCXX11AttributeExtension(Attrs);
|
||||||
|
Attrs.addAll(PrefixAttrs.begin(), PrefixAttrs.end());
|
||||||
|
|
||||||
if (InvalidDeclarator)
|
if (InvalidDeclarator)
|
||||||
SkipUntil(tok::comma, tok::semi, StopBeforeMatch);
|
SkipUntil(tok::comma, tok::semi, StopBeforeMatch);
|
||||||
|
@ -2639,8 +2636,6 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
|
||||||
MaybeParseMicrosoftAttributes(attrs);
|
MaybeParseMicrosoftAttributes(attrs);
|
||||||
|
|
||||||
if (Tok.is(tok::kw_using)) {
|
if (Tok.is(tok::kw_using)) {
|
||||||
ProhibitAttributes(attrs);
|
|
||||||
|
|
||||||
// Eat 'using'.
|
// Eat 'using'.
|
||||||
SourceLocation UsingLoc = ConsumeToken();
|
SourceLocation UsingLoc = ConsumeToken();
|
||||||
|
|
||||||
|
@ -2659,7 +2654,7 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
|
||||||
SourceLocation DeclEnd;
|
SourceLocation DeclEnd;
|
||||||
// Otherwise, it must be a using-declaration or an alias-declaration.
|
// Otherwise, it must be a using-declaration or an alias-declaration.
|
||||||
return ParseUsingDeclaration(DeclaratorContext::Member, TemplateInfo,
|
return ParseUsingDeclaration(DeclaratorContext::Member, TemplateInfo,
|
||||||
UsingLoc, DeclEnd, AS);
|
UsingLoc, DeclEnd, attrs, AS);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hold late-parsed attributes so we can attach a Decl to them later.
|
// Hold late-parsed attributes so we can attach a Decl to them later.
|
||||||
|
|
|
@ -2446,6 +2446,13 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr(
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
|
static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
|
||||||
|
if (isa<UsingDecl, UnresolvedUsingTypenameDecl, UnresolvedUsingValueDecl>(
|
||||||
|
D)) {
|
||||||
|
S.Diag(AL.getRange().getBegin(), diag::warn_deprecated_ignored_on_using)
|
||||||
|
<< AL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!AL.checkExactlyNumArgs(S, 1))
|
if (!AL.checkExactlyNumArgs(S, 1))
|
||||||
return;
|
return;
|
||||||
IdentifierLoc *Platform = AL.getArgAsIdent(0);
|
IdentifierLoc *Platform = AL.getArgAsIdent(0);
|
||||||
|
@ -7257,6 +7264,11 @@ static void handleDeprecatedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
|
||||||
// namespace.
|
// namespace.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
} else if (isa<UsingDecl, UnresolvedUsingTypenameDecl,
|
||||||
|
UnresolvedUsingValueDecl>(D)) {
|
||||||
|
S.Diag(AL.getRange().getBegin(), diag::warn_deprecated_ignored_on_using)
|
||||||
|
<< AL;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle the cases where the attribute has a text message.
|
// Handle the cases where the attribute has a text message.
|
||||||
|
|
|
@ -12071,9 +12071,9 @@ NamedDecl *Sema::BuildUsingDeclaration(
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
DeclContext *LookupContext = computeDeclContext(SS);
|
DeclContext *LookupContext = computeDeclContext(SS);
|
||||||
NamedDecl *D;
|
|
||||||
NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context);
|
NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context);
|
||||||
if (!LookupContext || EllipsisLoc.isValid()) {
|
if (!LookupContext || EllipsisLoc.isValid()) {
|
||||||
|
NamedDecl *D;
|
||||||
if (HasTypenameKeyword) {
|
if (HasTypenameKeyword) {
|
||||||
// FIXME: not all declaration name kinds are legal here
|
// FIXME: not all declaration name kinds are legal here
|
||||||
D = UnresolvedUsingTypenameDecl::Create(Context, CurContext,
|
D = UnresolvedUsingTypenameDecl::Create(Context, CurContext,
|
||||||
|
@ -12087,6 +12087,7 @@ NamedDecl *Sema::BuildUsingDeclaration(
|
||||||
}
|
}
|
||||||
D->setAccess(AS);
|
D->setAccess(AS);
|
||||||
CurContext->addDecl(D);
|
CurContext->addDecl(D);
|
||||||
|
ProcessDeclAttributeList(S, D, AttrList);
|
||||||
return D;
|
return D;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12096,6 +12097,7 @@ NamedDecl *Sema::BuildUsingDeclaration(
|
||||||
UsingName, HasTypenameKeyword);
|
UsingName, HasTypenameKeyword);
|
||||||
UD->setAccess(AS);
|
UD->setAccess(AS);
|
||||||
CurContext->addDecl(UD);
|
CurContext->addDecl(UD);
|
||||||
|
ProcessDeclAttributeList(S, UD, AttrList);
|
||||||
UD->setInvalidDecl(Invalid);
|
UD->setInvalidDecl(Invalid);
|
||||||
return UD;
|
return UD;
|
||||||
};
|
};
|
||||||
|
|
|
@ -131,12 +131,12 @@ extern "C++" [[]] { } // expected-error {{an attribute list cannot appear here}}
|
||||||
[[]] static_assert(true, ""); //expected-error {{an attribute list cannot appear here}}
|
[[]] static_assert(true, ""); //expected-error {{an attribute list cannot appear here}}
|
||||||
[[]] asm(""); // expected-error {{an attribute list cannot appear here}}
|
[[]] asm(""); // expected-error {{an attribute list cannot appear here}}
|
||||||
|
|
||||||
[[]] using ns::i; // expected-error {{an attribute list cannot appear here}}
|
[[]] using ns::i;
|
||||||
[[unknown]] using namespace ns; // expected-warning {{unknown attribute 'unknown' ignored}}
|
[[unknown]] using namespace ns; // expected-warning {{unknown attribute 'unknown' ignored}}
|
||||||
[[noreturn]] using namespace ns; // expected-error {{'noreturn' attribute only applies to functions}}
|
[[noreturn]] using namespace ns; // expected-error {{'noreturn' attribute only applies to functions}}
|
||||||
namespace [[]] ns2 {} // expected-warning {{attributes on a namespace declaration are a C++17 extension}}
|
namespace [[]] ns2 {} // expected-warning {{attributes on a namespace declaration are a C++17 extension}}
|
||||||
|
|
||||||
using [[]] alignas(4) [[]] ns::i; // expected-error {{an attribute list cannot appear here}}
|
using[[]] alignas(4)[[]] ns::i; // expected-error {{an attribute list cannot appear here}} expected-error {{'alignas' attribute only applies to variables, data members and tag types}} expected-warning {{ISO C++}}
|
||||||
using [[]] alignas(4) [[]] foobar = int; // expected-error {{an attribute list cannot appear here}} expected-error {{'alignas' attribute only applies to}}
|
using [[]] alignas(4) [[]] foobar = int; // expected-error {{an attribute list cannot appear here}} expected-error {{'alignas' attribute only applies to}}
|
||||||
|
|
||||||
void bad_attributes_in_do_while() {
|
void bad_attributes_in_do_while() {
|
||||||
|
@ -157,7 +157,16 @@ void bad_attributes_in_do_while() {
|
||||||
[[]] using T = int; // expected-error {{an attribute list cannot appear here}}
|
[[]] using T = int; // expected-error {{an attribute list cannot appear here}}
|
||||||
using T [[]] = int; // ok
|
using T [[]] = int; // ok
|
||||||
template<typename T> using U [[]] = T;
|
template<typename T> using U [[]] = T;
|
||||||
using ns::i [[]]; // expected-error {{an attribute list cannot appear here}}
|
using ns::i [[]];
|
||||||
|
using ns::i [[]], ns::i [[]]; // expected-warning {{use of multiple declarators in a single using declaration is a C++17 extension}}
|
||||||
|
struct using_in_struct_base {
|
||||||
|
typedef int i, j, k, l;
|
||||||
|
};
|
||||||
|
struct using_in_struct : using_in_struct_base {
|
||||||
|
[[]] using using_in_struct_base::i;
|
||||||
|
using using_in_struct_base::j [[]];
|
||||||
|
[[]] using using_in_struct_base::k [[]], using_in_struct_base::l [[]]; // expected-warning {{use of multiple declarators in a single using declaration is a C++17 extension}}
|
||||||
|
};
|
||||||
using [[]] ns::i; // expected-error {{an attribute list cannot appear here}}
|
using [[]] ns::i; // expected-error {{an attribute list cannot appear here}}
|
||||||
using T [[unknown]] = int; // expected-warning {{unknown attribute 'unknown' ignored}}
|
using T [[unknown]] = int; // expected-warning {{unknown attribute 'unknown' ignored}}
|
||||||
using T [[noreturn]] = int; // expected-error {{'noreturn' attribute only applies to functions}}
|
using T [[noreturn]] = int; // expected-error {{'noreturn' attribute only applies to functions}}
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
// RUN: %clang_cc1 -pedantic -triple x86_64-apple-macos11 -std=c++20 -fsyntax-only -verify %s
|
||||||
|
|
||||||
|
static_assert(__has_extension(cxx_attributes_on_using_declarations), "");
|
||||||
|
|
||||||
|
namespace NS { typedef int x; }
|
||||||
|
|
||||||
|
[[clang::annotate("foo")]] using NS::x; // expected-warning{{ISO C++ does not allow an attribute list to appear here}}
|
||||||
|
|
||||||
|
|
||||||
|
[[deprecated]] using NS::x; // expected-warning {{'deprecated' currently has no effect on a using declaration}} expected-warning{{ISO C++ does not allow}}
|
||||||
|
using NS::x [[deprecated]]; // expected-warning {{'deprecated' currently has no effect on a using declaration}} expected-warning{{ISO C++ does not allow}}
|
||||||
|
using NS::x __attribute__((deprecated)); // expected-warning {{'deprecated' currently has no effect on a using declaration}}
|
||||||
|
using NS::x __attribute__((availability(macos,introduced=1))); // expected-warning {{'availability' currently has no effect on a using declaration}}
|
||||||
|
|
||||||
|
[[clang::availability(macos,introduced=1)]] using NS::x; // expected-warning {{'availability' currently has no effect on a using declaration}} expected-warning{{ISO C++ does not allow}}
|
||||||
|
|
||||||
|
// expected-warning@+1 3 {{ISO C++ does not allow an attribute list to appear here}}
|
||||||
|
[[clang::annotate("A")]] using NS::x [[clang::annotate("Y")]], NS::x [[clang::annotate("Z")]];
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct S : T {
|
||||||
|
[[deprecated]] using typename T::x; // expected-warning{{ISO C++ does not allow}} expected-warning {{'deprecated' currently has no effect on a using declaration}}
|
||||||
|
[[deprecated]] using T::y; // expected-warning{{ISO C++ does not allow}} expected-warning {{'deprecated' currently has no effect on a using declaration}}
|
||||||
|
|
||||||
|
using typename T::z [[deprecated]]; // expected-warning{{ISO C++ does not allow}} expected-warning {{'deprecated' currently has no effect on a using declaration}}
|
||||||
|
using T::a [[deprecated]]; // expected-warning{{ISO C++ does not allow}} expected-warning {{'deprecated' currently has no effect on a using declaration}}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Base {};
|
||||||
|
|
||||||
|
template <class B>
|
||||||
|
struct DepBase1 : B {
|
||||||
|
using B::B [[]];
|
||||||
|
|
||||||
|
};
|
||||||
|
template <class B>
|
||||||
|
struct DepBase2 : B {
|
||||||
|
using B::B __attribute__(());
|
||||||
|
};
|
||||||
|
|
||||||
|
DepBase1<Base> db1;
|
||||||
|
DepBase2<Base> db2;
|
Loading…
Reference in New Issue