forked from OSchip/llvm-project
[c++1z] P0195R2: Allow multiple using-declarators in a single using-declaration.
llvm-svn: 289905
This commit is contained in:
parent
53f14c78b5
commit
6f1daa4660
|
@ -741,6 +741,15 @@ def err_alias_declaration_not_identifier : Error<
|
||||||
def err_alias_declaration_specialization : Error<
|
def err_alias_declaration_specialization : Error<
|
||||||
"%select{partial specialization|explicit specialization|explicit instantiation}0 of alias templates is not permitted">;
|
"%select{partial specialization|explicit specialization|explicit instantiation}0 of alias templates is not permitted">;
|
||||||
|
|
||||||
|
// C++1z using-declaration pack expansions
|
||||||
|
def ext_multi_using_declaration : ExtWarn<
|
||||||
|
"use of multiple declarators in a single using declaration is "
|
||||||
|
"a C++1z extension">, InGroup<CXX1z>;
|
||||||
|
def warn_cxx1z_compat_multi_using_declaration : Warning<
|
||||||
|
"use of multiple declarators in a single using declaration is "
|
||||||
|
"incompatible with C++ standards before C++1z">,
|
||||||
|
InGroup<CXXPre1zCompat>, DefaultIgnore;
|
||||||
|
|
||||||
// C++11 override control
|
// C++11 override control
|
||||||
def ext_override_control_keyword : ExtWarn<
|
def ext_override_control_keyword : ExtWarn<
|
||||||
"'%0' keyword is a C++11 extension">, InGroup<CXX11>;
|
"'%0' keyword is a C++11 extension">, InGroup<CXX11>;
|
||||||
|
|
|
@ -1261,6 +1261,11 @@ private:
|
||||||
ParsedAttributesWithRange(AttributeFactory &factory)
|
ParsedAttributesWithRange(AttributeFactory &factory)
|
||||||
: ParsedAttributes(factory) {}
|
: ParsedAttributes(factory) {}
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
ParsedAttributes::clear();
|
||||||
|
Range = SourceRange();
|
||||||
|
}
|
||||||
|
|
||||||
SourceRange Range;
|
SourceRange Range;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2418,21 +2423,41 @@ private:
|
||||||
BalancedDelimiterTracker &Tracker);
|
BalancedDelimiterTracker &Tracker);
|
||||||
Decl *ParseLinkage(ParsingDeclSpec &DS, unsigned Context);
|
Decl *ParseLinkage(ParsingDeclSpec &DS, unsigned Context);
|
||||||
Decl *ParseExportDeclaration();
|
Decl *ParseExportDeclaration();
|
||||||
Decl *ParseUsingDirectiveOrDeclaration(unsigned Context,
|
DeclGroupPtrTy ParseUsingDirectiveOrDeclaration(
|
||||||
const ParsedTemplateInfo &TemplateInfo,
|
unsigned Context, const ParsedTemplateInfo &TemplateInfo,
|
||||||
SourceLocation &DeclEnd,
|
SourceLocation &DeclEnd, ParsedAttributesWithRange &attrs);
|
||||||
ParsedAttributesWithRange &attrs,
|
|
||||||
Decl **OwnedType = nullptr);
|
|
||||||
Decl *ParseUsingDirective(unsigned Context,
|
Decl *ParseUsingDirective(unsigned Context,
|
||||||
SourceLocation UsingLoc,
|
SourceLocation UsingLoc,
|
||||||
SourceLocation &DeclEnd,
|
SourceLocation &DeclEnd,
|
||||||
ParsedAttributes &attrs);
|
ParsedAttributes &attrs);
|
||||||
Decl *ParseUsingDeclaration(unsigned Context,
|
|
||||||
|
struct UsingDeclarator {
|
||||||
|
SourceLocation TypenameLoc;
|
||||||
|
CXXScopeSpec SS;
|
||||||
|
SourceLocation TemplateKWLoc;
|
||||||
|
UnqualifiedId Name;
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
TypenameLoc = TemplateKWLoc = SourceLocation();
|
||||||
|
SS.clear();
|
||||||
|
Name.clear();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
bool ParseUsingDeclarator(unsigned Context, UsingDeclarator &D);
|
||||||
|
DeclGroupPtrTy ParseUsingDeclaration(unsigned Context,
|
||||||
const ParsedTemplateInfo &TemplateInfo,
|
const ParsedTemplateInfo &TemplateInfo,
|
||||||
SourceLocation UsingLoc,
|
SourceLocation UsingLoc,
|
||||||
SourceLocation &DeclEnd,
|
SourceLocation &DeclEnd,
|
||||||
AccessSpecifier AS = AS_none,
|
AccessSpecifier AS = AS_none);
|
||||||
Decl **OwnedType = nullptr);
|
Decl *ParseAliasTemplate(const ParsedTemplateInfo &TemplateInfo,
|
||||||
|
SourceLocation &DeclEnd, AccessSpecifier AS,
|
||||||
|
ParsedAttributesWithRange &MisplacedAttrs1);
|
||||||
|
Decl *ParseAliasDeclarationAfterDeclarator(
|
||||||
|
const ParsedTemplateInfo &TemplateInfo, SourceLocation UsingLoc,
|
||||||
|
UsingDeclarator &D, SourceLocation &DeclEnd, AccessSpecifier AS,
|
||||||
|
ParsedAttributes &Attrs, Decl **OwnedType = nullptr);
|
||||||
|
|
||||||
Decl *ParseStaticAssertDeclaration(SourceLocation &DeclEnd);
|
Decl *ParseStaticAssertDeclaration(SourceLocation &DeclEnd);
|
||||||
Decl *ParseNamespaceAlias(SourceLocation NamespaceLoc,
|
Decl *ParseNamespaceAlias(SourceLocation NamespaceLoc,
|
||||||
SourceLocation AliasLoc, IdentifierInfo *Alias,
|
SourceLocation AliasLoc, IdentifierInfo *Alias,
|
||||||
|
|
|
@ -4341,12 +4341,10 @@ public:
|
||||||
|
|
||||||
Decl *ActOnUsingDeclaration(Scope *CurScope,
|
Decl *ActOnUsingDeclaration(Scope *CurScope,
|
||||||
AccessSpecifier AS,
|
AccessSpecifier AS,
|
||||||
bool HasUsingKeyword,
|
|
||||||
SourceLocation UsingLoc,
|
SourceLocation UsingLoc,
|
||||||
CXXScopeSpec &SS,
|
CXXScopeSpec &SS,
|
||||||
UnqualifiedId &Name,
|
UnqualifiedId &Name,
|
||||||
AttributeList *AttrList,
|
AttributeList *AttrList,
|
||||||
bool HasTypenameKeyword,
|
|
||||||
SourceLocation TypenameLoc);
|
SourceLocation TypenameLoc);
|
||||||
Decl *ActOnAliasDeclaration(Scope *CurScope,
|
Decl *ActOnAliasDeclaration(Scope *CurScope,
|
||||||
AccessSpecifier AS,
|
AccessSpecifier AS,
|
||||||
|
|
|
@ -1506,7 +1506,6 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(unsigned Context,
|
||||||
ObjCDeclContextSwitch ObjCDC(*this);
|
ObjCDeclContextSwitch ObjCDC(*this);
|
||||||
|
|
||||||
Decl *SingleDecl = nullptr;
|
Decl *SingleDecl = nullptr;
|
||||||
Decl *OwnedType = nullptr;
|
|
||||||
switch (Tok.getKind()) {
|
switch (Tok.getKind()) {
|
||||||
case tok::kw_template:
|
case tok::kw_template:
|
||||||
case tok::kw_export:
|
case tok::kw_export:
|
||||||
|
@ -1526,9 +1525,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(unsigned Context,
|
||||||
ProhibitAttributes(attrs);
|
ProhibitAttributes(attrs);
|
||||||
return ParseNamespace(Context, DeclEnd);
|
return ParseNamespace(Context, DeclEnd);
|
||||||
case tok::kw_using:
|
case tok::kw_using:
|
||||||
SingleDecl = ParseUsingDirectiveOrDeclaration(Context, ParsedTemplateInfo(),
|
return ParseUsingDirectiveOrDeclaration(Context, ParsedTemplateInfo(),
|
||||||
DeclEnd, attrs, &OwnedType);
|
DeclEnd, attrs);
|
||||||
break;
|
|
||||||
case tok::kw_static_assert:
|
case tok::kw_static_assert:
|
||||||
case tok::kw__Static_assert:
|
case tok::kw__Static_assert:
|
||||||
ProhibitAttributes(attrs);
|
ProhibitAttributes(attrs);
|
||||||
|
@ -1539,9 +1537,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(unsigned Context,
|
||||||
}
|
}
|
||||||
|
|
||||||
// This routine returns a DeclGroup, if the thing we parsed only contains a
|
// This routine returns a DeclGroup, if the thing we parsed only contains a
|
||||||
// single decl, convert it now. Alias declarations can also declare a type;
|
// single decl, convert it now.
|
||||||
// include that too if it is present.
|
return Actions.ConvertDeclToDeclGroup(SingleDecl);
|
||||||
return Actions.ConvertDeclToDeclGroup(SingleDecl, OwnedType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// simple-declaration: [C99 6.7: declaration] [C++ 7p1: dcl.dcl]
|
/// simple-declaration: [C99 6.7: declaration] [C++ 7p1: dcl.dcl]
|
||||||
|
|
|
@ -421,11 +421,11 @@ Decl *Parser::ParseExportDeclaration() {
|
||||||
|
|
||||||
/// ParseUsingDirectiveOrDeclaration - Parse C++ using using-declaration or
|
/// ParseUsingDirectiveOrDeclaration - Parse C++ using using-declaration or
|
||||||
/// using-directive. Assumes that current token is 'using'.
|
/// using-directive. Assumes that current token is 'using'.
|
||||||
Decl *Parser::ParseUsingDirectiveOrDeclaration(unsigned Context,
|
Parser::DeclGroupPtrTy
|
||||||
|
Parser::ParseUsingDirectiveOrDeclaration(unsigned Context,
|
||||||
const ParsedTemplateInfo &TemplateInfo,
|
const ParsedTemplateInfo &TemplateInfo,
|
||||||
SourceLocation &DeclEnd,
|
SourceLocation &DeclEnd,
|
||||||
ParsedAttributesWithRange &attrs,
|
ParsedAttributesWithRange &attrs) {
|
||||||
Decl **OwnedType) {
|
|
||||||
assert(Tok.is(tok::kw_using) && "Not using token");
|
assert(Tok.is(tok::kw_using) && "Not using token");
|
||||||
ObjCDeclContextSwitch ObjCDC(*this);
|
ObjCDeclContextSwitch ObjCDC(*this);
|
||||||
|
|
||||||
|
@ -447,7 +447,8 @@ Decl *Parser::ParseUsingDirectiveOrDeclaration(unsigned Context,
|
||||||
<< 0 /* directive */ << R << FixItHint::CreateRemoval(R);
|
<< 0 /* directive */ << R << FixItHint::CreateRemoval(R);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ParseUsingDirective(Context, UsingLoc, DeclEnd, attrs);
|
Decl *UsingDir = ParseUsingDirective(Context, UsingLoc, DeclEnd, attrs);
|
||||||
|
return Actions.ConvertDeclToDeclGroup(UsingDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, it must be a using-declaration or an alias-declaration.
|
// Otherwise, it must be a using-declaration or an alias-declaration.
|
||||||
|
@ -456,7 +457,7 @@ Decl *Parser::ParseUsingDirectiveOrDeclaration(unsigned Context,
|
||||||
ProhibitAttributes(attrs);
|
ProhibitAttributes(attrs);
|
||||||
|
|
||||||
return ParseUsingDeclaration(Context, TemplateInfo, UsingLoc, DeclEnd,
|
return ParseUsingDeclaration(Context, TemplateInfo, UsingLoc, DeclEnd,
|
||||||
AS_none, OwnedType);
|
AS_none);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ParseUsingDirective - Parse C++ using-directive, assumes
|
/// ParseUsingDirective - Parse C++ using-directive, assumes
|
||||||
|
@ -522,58 +523,31 @@ Decl *Parser::ParseUsingDirective(unsigned Context,
|
||||||
IdentLoc, NamespcName, attrs.getList());
|
IdentLoc, NamespcName, attrs.getList());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ParseUsingDeclaration - Parse C++ using-declaration or alias-declaration.
|
/// Parse a using-declarator (or the identifier in a C++11 alias-declaration).
|
||||||
/// Assumes that 'using' was already seen.
|
|
||||||
///
|
///
|
||||||
/// using-declaration: [C++ 7.3.p3: namespace.udecl]
|
/// using-declarator:
|
||||||
/// 'using' 'typename'[opt] ::[opt] nested-name-specifier
|
/// 'typename'[opt] nested-name-specifier unqualified-id
|
||||||
/// unqualified-id
|
|
||||||
/// 'using' :: unqualified-id
|
|
||||||
///
|
///
|
||||||
/// alias-declaration: C++11 [dcl.dcl]p1
|
bool Parser::ParseUsingDeclarator(unsigned Context, UsingDeclarator &D) {
|
||||||
/// 'using' identifier attribute-specifier-seq[opt] = type-id ;
|
D.clear();
|
||||||
///
|
|
||||||
Decl *Parser::ParseUsingDeclaration(unsigned Context,
|
|
||||||
const ParsedTemplateInfo &TemplateInfo,
|
|
||||||
SourceLocation UsingLoc,
|
|
||||||
SourceLocation &DeclEnd,
|
|
||||||
AccessSpecifier AS,
|
|
||||||
Decl **OwnedType) {
|
|
||||||
CXXScopeSpec SS;
|
|
||||||
SourceLocation TypenameLoc;
|
|
||||||
bool HasTypenameKeyword = false;
|
|
||||||
|
|
||||||
// Check for misplaced attributes before the identifier in an
|
|
||||||
// alias-declaration.
|
|
||||||
ParsedAttributesWithRange MisplacedAttrs(AttrFactory);
|
|
||||||
MaybeParseCXX11Attributes(MisplacedAttrs);
|
|
||||||
|
|
||||||
// Ignore optional 'typename'.
|
// Ignore optional 'typename'.
|
||||||
// FIXME: This is wrong; we should parse this as a typename-specifier.
|
// FIXME: This is wrong; we should parse this as a typename-specifier.
|
||||||
if (TryConsumeToken(tok::kw_typename, TypenameLoc))
|
TryConsumeToken(tok::kw_typename, D.TypenameLoc);
|
||||||
HasTypenameKeyword = true;
|
|
||||||
|
|
||||||
if (Tok.is(tok::kw___super)) {
|
if (Tok.is(tok::kw___super)) {
|
||||||
Diag(Tok.getLocation(), diag::err_super_in_using_declaration);
|
Diag(Tok.getLocation(), diag::err_super_in_using_declaration);
|
||||||
SkipUntil(tok::semi);
|
return true;
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse nested-name-specifier.
|
// Parse nested-name-specifier.
|
||||||
IdentifierInfo *LastII = nullptr;
|
IdentifierInfo *LastII = nullptr;
|
||||||
ParseOptionalCXXScopeSpecifier(SS, nullptr, /*EnteringContext=*/false,
|
ParseOptionalCXXScopeSpecifier(D.SS, nullptr, /*EnteringContext=*/false,
|
||||||
/*MayBePseudoDtor=*/nullptr,
|
/*MayBePseudoDtor=*/nullptr,
|
||||||
/*IsTypename=*/false,
|
/*IsTypename=*/false,
|
||||||
/*LastII=*/&LastII);
|
/*LastII=*/&LastII);
|
||||||
|
if (D.SS.isInvalid())
|
||||||
// Check nested-name specifier.
|
return true;
|
||||||
if (SS.isInvalid()) {
|
|
||||||
SkipUntil(tok::semi);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
SourceLocation TemplateKWLoc;
|
|
||||||
UnqualifiedId Name;
|
|
||||||
|
|
||||||
// Parse the unqualified-id. We allow parsing of both constructor and
|
// Parse the unqualified-id. We allow parsing of both constructor and
|
||||||
// destructor names and allow the action module to diagnose any semantic
|
// destructor names and allow the action module to diagnose any semantic
|
||||||
|
@ -587,31 +561,68 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
|
||||||
// constructor.
|
// constructor.
|
||||||
if (getLangOpts().CPlusPlus11 && Context == Declarator::MemberContext &&
|
if (getLangOpts().CPlusPlus11 && Context == Declarator::MemberContext &&
|
||||||
Tok.is(tok::identifier) && NextToken().is(tok::semi) &&
|
Tok.is(tok::identifier) && NextToken().is(tok::semi) &&
|
||||||
SS.isNotEmpty() && LastII == Tok.getIdentifierInfo() &&
|
D.SS.isNotEmpty() && LastII == Tok.getIdentifierInfo() &&
|
||||||
!SS.getScopeRep()->getAsNamespace() &&
|
!D.SS.getScopeRep()->getAsNamespace() &&
|
||||||
!SS.getScopeRep()->getAsNamespaceAlias()) {
|
!D.SS.getScopeRep()->getAsNamespaceAlias()) {
|
||||||
SourceLocation IdLoc = ConsumeToken();
|
SourceLocation IdLoc = ConsumeToken();
|
||||||
ParsedType Type = Actions.getInheritingConstructorName(SS, IdLoc, *LastII);
|
ParsedType Type =
|
||||||
Name.setConstructorName(Type, IdLoc, IdLoc);
|
Actions.getInheritingConstructorName(D.SS, IdLoc, *LastII);
|
||||||
} else if (ParseUnqualifiedId(
|
D.Name.setConstructorName(Type, IdLoc, IdLoc);
|
||||||
SS, /*EnteringContext=*/false,
|
} else {
|
||||||
|
if (ParseUnqualifiedId(
|
||||||
|
D.SS, /*EnteringContext=*/false,
|
||||||
/*AllowDestructorName=*/true,
|
/*AllowDestructorName=*/true,
|
||||||
/*AllowConstructorName=*/!(Tok.is(tok::identifier) &&
|
/*AllowConstructorName=*/!(Tok.is(tok::identifier) &&
|
||||||
NextToken().is(tok::equal)),
|
NextToken().is(tok::equal)),
|
||||||
nullptr, TemplateKWLoc, Name)) {
|
nullptr, D.TemplateKWLoc, D.Name))
|
||||||
SkipUntil(tok::semi);
|
return true;
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: Parse optional ellipsis
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ParseUsingDeclaration - Parse C++ using-declaration or alias-declaration.
|
||||||
|
/// Assumes that 'using' was already seen.
|
||||||
|
///
|
||||||
|
/// using-declaration: [C++ 7.3.p3: namespace.udecl]
|
||||||
|
/// 'using' using-declarator-list[opt] ;
|
||||||
|
///
|
||||||
|
/// using-declarator-list: [C++1z]
|
||||||
|
/// using-declarator '...'[opt]
|
||||||
|
/// using-declarator-list ',' using-declarator '...'[opt]
|
||||||
|
///
|
||||||
|
/// using-declarator-list: [C++98-14]
|
||||||
|
/// using-declarator
|
||||||
|
///
|
||||||
|
/// alias-declaration: C++11 [dcl.dcl]p1
|
||||||
|
/// 'using' identifier attribute-specifier-seq[opt] = type-id ;
|
||||||
|
///
|
||||||
|
Parser::DeclGroupPtrTy
|
||||||
|
Parser::ParseUsingDeclaration(unsigned Context,
|
||||||
|
const ParsedTemplateInfo &TemplateInfo,
|
||||||
|
SourceLocation UsingLoc, SourceLocation &DeclEnd,
|
||||||
|
AccessSpecifier AS) {
|
||||||
|
// Check for misplaced attributes before the identifier in an
|
||||||
|
// alias-declaration.
|
||||||
|
ParsedAttributesWithRange MisplacedAttrs(AttrFactory);
|
||||||
|
MaybeParseCXX11Attributes(MisplacedAttrs);
|
||||||
|
|
||||||
|
UsingDeclarator D;
|
||||||
|
bool InvalidDeclarator = ParseUsingDeclarator(Context, D);
|
||||||
|
|
||||||
ParsedAttributesWithRange Attrs(AttrFactory);
|
ParsedAttributesWithRange Attrs(AttrFactory);
|
||||||
MaybeParseGNUAttributes(Attrs);
|
MaybeParseGNUAttributes(Attrs);
|
||||||
MaybeParseCXX11Attributes(Attrs);
|
MaybeParseCXX11Attributes(Attrs);
|
||||||
|
|
||||||
// Maybe this is an alias-declaration.
|
// Maybe this is an alias-declaration.
|
||||||
TypeResult TypeAlias;
|
if (Tok.is(tok::equal)) {
|
||||||
bool IsAliasDecl = Tok.is(tok::equal);
|
if (InvalidDeclarator) {
|
||||||
Decl *DeclFromDeclSpec = nullptr;
|
SkipUntil(tok::semi);
|
||||||
if (IsAliasDecl) {
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
// If we had any misplaced attributes from earlier, this is where they
|
// If we had any misplaced attributes from earlier, this is where they
|
||||||
// should have been written.
|
// should have been written.
|
||||||
if (MisplacedAttrs.Range.isValid()) {
|
if (MisplacedAttrs.Range.isValid()) {
|
||||||
|
@ -623,76 +634,21 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
|
||||||
Attrs.takeAllFrom(MisplacedAttrs);
|
Attrs.takeAllFrom(MisplacedAttrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConsumeToken();
|
Decl *DeclFromDeclSpec = nullptr;
|
||||||
|
Decl *AD = ParseAliasDeclarationAfterDeclarator(
|
||||||
Diag(Tok.getLocation(), getLangOpts().CPlusPlus11 ?
|
TemplateInfo, UsingLoc, D, DeclEnd, AS, Attrs, &DeclFromDeclSpec);
|
||||||
diag::warn_cxx98_compat_alias_declaration :
|
return Actions.ConvertDeclToDeclGroup(AD, DeclFromDeclSpec);
|
||||||
diag::ext_alias_declaration);
|
|
||||||
|
|
||||||
// Type alias templates cannot be specialized.
|
|
||||||
int SpecKind = -1;
|
|
||||||
if (TemplateInfo.Kind == ParsedTemplateInfo::Template &&
|
|
||||||
Name.getKind() == UnqualifiedId::IK_TemplateId)
|
|
||||||
SpecKind = 0;
|
|
||||||
if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization)
|
|
||||||
SpecKind = 1;
|
|
||||||
if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation)
|
|
||||||
SpecKind = 2;
|
|
||||||
if (SpecKind != -1) {
|
|
||||||
SourceRange Range;
|
|
||||||
if (SpecKind == 0)
|
|
||||||
Range = SourceRange(Name.TemplateId->LAngleLoc,
|
|
||||||
Name.TemplateId->RAngleLoc);
|
|
||||||
else
|
|
||||||
Range = TemplateInfo.getSourceRange();
|
|
||||||
Diag(Range.getBegin(), diag::err_alias_declaration_specialization)
|
|
||||||
<< SpecKind << Range;
|
|
||||||
SkipUntil(tok::semi);
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Name must be an identifier.
|
|
||||||
if (Name.getKind() != UnqualifiedId::IK_Identifier) {
|
|
||||||
Diag(Name.StartLocation, diag::err_alias_declaration_not_identifier);
|
|
||||||
// No removal fixit: can't recover from this.
|
|
||||||
SkipUntil(tok::semi);
|
|
||||||
return nullptr;
|
|
||||||
} else if (HasTypenameKeyword)
|
|
||||||
Diag(TypenameLoc, diag::err_alias_declaration_not_identifier)
|
|
||||||
<< FixItHint::CreateRemoval(SourceRange(TypenameLoc,
|
|
||||||
SS.isNotEmpty() ? SS.getEndLoc() : TypenameLoc));
|
|
||||||
else if (SS.isNotEmpty())
|
|
||||||
Diag(SS.getBeginLoc(), diag::err_alias_declaration_not_identifier)
|
|
||||||
<< FixItHint::CreateRemoval(SS.getRange());
|
|
||||||
|
|
||||||
TypeAlias = ParseTypeName(nullptr, TemplateInfo.Kind
|
|
||||||
? Declarator::AliasTemplateContext
|
|
||||||
: Declarator::AliasDeclContext,
|
|
||||||
AS, &DeclFromDeclSpec, &Attrs);
|
|
||||||
if (OwnedType)
|
|
||||||
*OwnedType = DeclFromDeclSpec;
|
|
||||||
} else {
|
|
||||||
// C++11 attributes are not allowed on a using-declaration, but GNU ones
|
// C++11 attributes are not allowed on a using-declaration, but GNU ones
|
||||||
// are.
|
// are.
|
||||||
ProhibitAttributes(MisplacedAttrs);
|
ProhibitAttributes(MisplacedAttrs);
|
||||||
ProhibitAttributes(Attrs);
|
ProhibitAttributes(Attrs);
|
||||||
|
|
||||||
// Parse (optional) attributes (most likely GNU strong-using extension).
|
|
||||||
MaybeParseGNUAttributes(Attrs);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Eat ';'.
|
|
||||||
DeclEnd = Tok.getLocation();
|
|
||||||
if (ExpectAndConsume(tok::semi, diag::err_expected_after,
|
|
||||||
!Attrs.empty() ? "attributes list"
|
|
||||||
: IsAliasDecl ? "alias declaration"
|
|
||||||
: "using declaration"))
|
|
||||||
SkipUntil(tok::semi);
|
|
||||||
|
|
||||||
// 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:
|
||||||
// template <...> using id = type;
|
// template <...> using id = type;
|
||||||
if (TemplateInfo.Kind && !IsAliasDecl) {
|
if (TemplateInfo.Kind) {
|
||||||
SourceRange R = TemplateInfo.getSourceRange();
|
SourceRange R = TemplateInfo.getSourceRange();
|
||||||
Diag(UsingLoc, diag::err_templated_using_directive_declaration)
|
Diag(UsingLoc, diag::err_templated_using_directive_declaration)
|
||||||
<< 1 /* declaration */ << R << FixItHint::CreateRemoval(R);
|
<< 1 /* declaration */ << R << FixItHint::CreateRemoval(R);
|
||||||
|
@ -703,29 +659,184 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SmallVector<Decl *, 8> DeclsInGroup;
|
||||||
|
while (true) {
|
||||||
|
// Parse (optional) attributes (most likely GNU strong-using extension).
|
||||||
|
MaybeParseGNUAttributes(Attrs);
|
||||||
|
|
||||||
|
if (InvalidDeclarator)
|
||||||
|
SkipUntil(tok::comma, tok::semi, StopBeforeMatch);
|
||||||
|
else {
|
||||||
// "typename" keyword is allowed for identifiers only,
|
// "typename" keyword is allowed for identifiers only,
|
||||||
// because it may be a type definition.
|
// because it may be a type definition.
|
||||||
if (HasTypenameKeyword && Name.getKind() != UnqualifiedId::IK_Identifier) {
|
if (D.TypenameLoc.isValid() &&
|
||||||
Diag(Name.getSourceRange().getBegin(), diag::err_typename_identifiers_only)
|
D.Name.getKind() != UnqualifiedId::IK_Identifier) {
|
||||||
<< FixItHint::CreateRemoval(SourceRange(TypenameLoc));
|
Diag(D.Name.getSourceRange().getBegin(),
|
||||||
// Proceed parsing, but reset the HasTypenameKeyword flag.
|
diag::err_typename_identifiers_only)
|
||||||
HasTypenameKeyword = false;
|
<< FixItHint::CreateRemoval(SourceRange(D.TypenameLoc));
|
||||||
|
// Proceed parsing, but discard the typename keyword.
|
||||||
|
D.TypenameLoc = SourceLocation();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsAliasDecl) {
|
Decl *UD =
|
||||||
|
Actions.ActOnUsingDeclaration(getCurScope(), AS, UsingLoc, D.SS,
|
||||||
|
D.Name, Attrs.getList(), D.TypenameLoc);
|
||||||
|
if (UD)
|
||||||
|
DeclsInGroup.push_back(UD);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!TryConsumeToken(tok::comma))
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Parse another using-declarator.
|
||||||
|
Attrs.clear();
|
||||||
|
InvalidDeclarator = ParseUsingDeclarator(Context, D);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DeclsInGroup.size() > 1)
|
||||||
|
Diag(Tok.getLocation(), getLangOpts().CPlusPlus1z ?
|
||||||
|
diag::warn_cxx1z_compat_multi_using_declaration :
|
||||||
|
diag::ext_multi_using_declaration);
|
||||||
|
|
||||||
|
// Eat ';'.
|
||||||
|
DeclEnd = Tok.getLocation();
|
||||||
|
if (ExpectAndConsume(tok::semi, diag::err_expected_after,
|
||||||
|
!Attrs.empty() ? "attributes list"
|
||||||
|
: "using declaration"))
|
||||||
|
SkipUntil(tok::semi);
|
||||||
|
|
||||||
|
return Actions.BuildDeclaratorGroup(DeclsInGroup, /*MayContainAuto*/false);
|
||||||
|
}
|
||||||
|
|
||||||
|
Decl *Parser::ParseAliasTemplate(const ParsedTemplateInfo &TemplateInfo,
|
||||||
|
SourceLocation &DeclEnd, AccessSpecifier AS,
|
||||||
|
ParsedAttributesWithRange &MisplacedAttrs1) {
|
||||||
|
assert(Tok.is(tok::kw_using) && "Not using token");
|
||||||
|
ObjCDeclContextSwitch ObjCDC(*this);
|
||||||
|
|
||||||
|
// Eat 'using'.
|
||||||
|
SourceLocation UsingLoc = ConsumeToken();
|
||||||
|
if (Tok.is(tok::code_completion)) {
|
||||||
|
Actions.CodeCompleteUsing(getCurScope());
|
||||||
|
cutOffParsing();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 'using namespace' means this is a using-directive.
|
||||||
|
if (Tok.is(tok::kw_namespace)) {
|
||||||
|
SourceRange R = TemplateInfo.getSourceRange();
|
||||||
|
Diag(UsingLoc, diag::err_templated_using_directive_declaration)
|
||||||
|
<< 0 /* directive */ << R;
|
||||||
|
SkipUntil(tok::semi);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for misplaced attributes before the identifier.
|
||||||
|
ParsedAttributesWithRange MisplacedAttrs2(AttrFactory);
|
||||||
|
MaybeParseCXX11Attributes(MisplacedAttrs2);
|
||||||
|
|
||||||
|
// FIXME: Just parse an identifier here?
|
||||||
|
UsingDeclarator D;
|
||||||
|
if (ParseUsingDeclarator(Declarator::FileContext, D)) {
|
||||||
|
SkipUntil(tok::semi);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
ParsedAttributesWithRange Attrs(AttrFactory);
|
||||||
|
|
||||||
|
// If we had any misplaced attributes from earlier, this is where they
|
||||||
|
// should have been written.
|
||||||
|
for (auto *MisplacedAttrs : {&MisplacedAttrs1, &MisplacedAttrs2}) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MaybeParseGNUAttributes(Attrs);
|
||||||
|
MaybeParseCXX11Attributes(Attrs);
|
||||||
|
|
||||||
|
return ParseAliasDeclarationAfterDeclarator(TemplateInfo, UsingLoc, D,
|
||||||
|
DeclEnd, AS, Attrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
Decl *Parser::ParseAliasDeclarationAfterDeclarator(
|
||||||
|
const ParsedTemplateInfo &TemplateInfo, SourceLocation UsingLoc,
|
||||||
|
UsingDeclarator &D, SourceLocation &DeclEnd, AccessSpecifier AS,
|
||||||
|
ParsedAttributes &Attrs, Decl **OwnedType) {
|
||||||
|
if (ExpectAndConsume(tok::equal)) {
|
||||||
|
SkipUntil(tok::semi);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Diag(Tok.getLocation(), getLangOpts().CPlusPlus11 ?
|
||||||
|
diag::warn_cxx98_compat_alias_declaration :
|
||||||
|
diag::ext_alias_declaration);
|
||||||
|
|
||||||
|
// Type alias templates cannot be specialized.
|
||||||
|
int SpecKind = -1;
|
||||||
|
if (TemplateInfo.Kind == ParsedTemplateInfo::Template &&
|
||||||
|
D.Name.getKind() == UnqualifiedId::IK_TemplateId)
|
||||||
|
SpecKind = 0;
|
||||||
|
if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization)
|
||||||
|
SpecKind = 1;
|
||||||
|
if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation)
|
||||||
|
SpecKind = 2;
|
||||||
|
if (SpecKind != -1) {
|
||||||
|
SourceRange Range;
|
||||||
|
if (SpecKind == 0)
|
||||||
|
Range = SourceRange(D.Name.TemplateId->LAngleLoc,
|
||||||
|
D.Name.TemplateId->RAngleLoc);
|
||||||
|
else
|
||||||
|
Range = TemplateInfo.getSourceRange();
|
||||||
|
Diag(Range.getBegin(), diag::err_alias_declaration_specialization)
|
||||||
|
<< SpecKind << Range;
|
||||||
|
SkipUntil(tok::semi);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name must be an identifier.
|
||||||
|
if (D.Name.getKind() != UnqualifiedId::IK_Identifier) {
|
||||||
|
Diag(D.Name.StartLocation, diag::err_alias_declaration_not_identifier);
|
||||||
|
// No removal fixit: can't recover from this.
|
||||||
|
SkipUntil(tok::semi);
|
||||||
|
return nullptr;
|
||||||
|
} else if (D.TypenameLoc.isValid())
|
||||||
|
Diag(D.TypenameLoc, diag::err_alias_declaration_not_identifier)
|
||||||
|
<< FixItHint::CreateRemoval(SourceRange(
|
||||||
|
D.TypenameLoc,
|
||||||
|
D.SS.isNotEmpty() ? D.SS.getEndLoc() : D.TypenameLoc));
|
||||||
|
else if (D.SS.isNotEmpty())
|
||||||
|
Diag(D.SS.getBeginLoc(), diag::err_alias_declaration_not_identifier)
|
||||||
|
<< FixItHint::CreateRemoval(D.SS.getRange());
|
||||||
|
|
||||||
|
Decl *DeclFromDeclSpec = nullptr;
|
||||||
|
TypeResult TypeAlias =
|
||||||
|
ParseTypeName(nullptr,
|
||||||
|
TemplateInfo.Kind ? Declarator::AliasTemplateContext
|
||||||
|
: Declarator::AliasDeclContext,
|
||||||
|
AS, &DeclFromDeclSpec, &Attrs);
|
||||||
|
if (OwnedType)
|
||||||
|
*OwnedType = DeclFromDeclSpec;
|
||||||
|
|
||||||
|
// Eat ';'.
|
||||||
|
DeclEnd = Tok.getLocation();
|
||||||
|
if (ExpectAndConsume(tok::semi, diag::err_expected_after,
|
||||||
|
!Attrs.empty() ? "attributes list"
|
||||||
|
: "alias declaration"))
|
||||||
|
SkipUntil(tok::semi);
|
||||||
|
|
||||||
TemplateParameterLists *TemplateParams = TemplateInfo.TemplateParams;
|
TemplateParameterLists *TemplateParams = TemplateInfo.TemplateParams;
|
||||||
MultiTemplateParamsArg TemplateParamsArg(
|
MultiTemplateParamsArg TemplateParamsArg(
|
||||||
TemplateParams ? TemplateParams->data() : nullptr,
|
TemplateParams ? TemplateParams->data() : nullptr,
|
||||||
TemplateParams ? TemplateParams->size() : 0);
|
TemplateParams ? TemplateParams->size() : 0);
|
||||||
return Actions.ActOnAliasDeclaration(getCurScope(), AS, TemplateParamsArg,
|
return Actions.ActOnAliasDeclaration(getCurScope(), AS, TemplateParamsArg,
|
||||||
UsingLoc, Name, Attrs.getList(),
|
UsingLoc, D.Name, Attrs.getList(),
|
||||||
TypeAlias, DeclFromDeclSpec);
|
TypeAlias, DeclFromDeclSpec);
|
||||||
}
|
|
||||||
|
|
||||||
return Actions.ActOnUsingDeclaration(getCurScope(), AS,
|
|
||||||
/* HasUsingKeyword */ true, UsingLoc,
|
|
||||||
SS, Name, Attrs.getList(),
|
|
||||||
HasTypenameKeyword, TypenameLoc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ParseStaticAssertDeclaration - Parse C++0x or C11 static_assert-declaration.
|
/// ParseStaticAssertDeclaration - Parse C++0x or C11 static_assert-declaration.
|
||||||
|
@ -2376,10 +2487,8 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
|
||||||
}
|
}
|
||||||
|
|
||||||
return DeclGroupPtrTy::make(DeclGroupRef(Actions.ActOnUsingDeclaration(
|
return DeclGroupPtrTy::make(DeclGroupRef(Actions.ActOnUsingDeclaration(
|
||||||
getCurScope(), AS,
|
getCurScope(), AS, /*UsingLoc*/SourceLocation(), SS, Name,
|
||||||
/* HasUsingKeyword */ false, SourceLocation(), SS, Name,
|
/*AttrList*/nullptr, /*TypenameLoc*/SourceLocation())));
|
||||||
/* AttrList */ nullptr,
|
|
||||||
/* HasTypenameKeyword */ false, SourceLocation())));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2434,8 +2543,8 @@ 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 DeclGroupPtrTy::make(DeclGroupRef(ParseUsingDeclaration(
|
return ParseUsingDeclaration(Declarator::MemberContext, TemplateInfo,
|
||||||
Declarator::MemberContext, TemplateInfo, UsingLoc, DeclEnd, AS)));
|
UsingLoc, DeclEnd, 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.
|
||||||
|
|
|
@ -196,9 +196,12 @@ Parser::ParseSingleDeclarationAfterTemplate(
|
||||||
ParsedAttributesWithRange prefixAttrs(AttrFactory);
|
ParsedAttributesWithRange prefixAttrs(AttrFactory);
|
||||||
MaybeParseCXX11Attributes(prefixAttrs);
|
MaybeParseCXX11Attributes(prefixAttrs);
|
||||||
|
|
||||||
if (Tok.is(tok::kw_using))
|
if (Tok.is(tok::kw_using)) {
|
||||||
return ParseUsingDirectiveOrDeclaration(Context, TemplateInfo, DeclEnd,
|
// FIXME: We should return the DeclGroup to the caller.
|
||||||
|
ParseUsingDirectiveOrDeclaration(Context, TemplateInfo, DeclEnd,
|
||||||
prefixAttrs);
|
prefixAttrs);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
// Parse the declaration specifiers, stealing any diagnostics from
|
// Parse the declaration specifiers, stealing any diagnostics from
|
||||||
// the template parameters.
|
// the template parameters.
|
||||||
|
|
|
@ -8532,12 +8532,10 @@ void Sema::PushUsingDirective(Scope *S, UsingDirectiveDecl *UDir) {
|
||||||
|
|
||||||
Decl *Sema::ActOnUsingDeclaration(Scope *S,
|
Decl *Sema::ActOnUsingDeclaration(Scope *S,
|
||||||
AccessSpecifier AS,
|
AccessSpecifier AS,
|
||||||
bool HasUsingKeyword,
|
|
||||||
SourceLocation UsingLoc,
|
SourceLocation UsingLoc,
|
||||||
CXXScopeSpec &SS,
|
CXXScopeSpec &SS,
|
||||||
UnqualifiedId &Name,
|
UnqualifiedId &Name,
|
||||||
AttributeList *AttrList,
|
AttributeList *AttrList,
|
||||||
bool HasTypenameKeyword,
|
|
||||||
SourceLocation TypenameLoc) {
|
SourceLocation TypenameLoc) {
|
||||||
assert(S->getFlags() & Scope::DeclScope && "Invalid Scope.");
|
assert(S->getFlags() & Scope::DeclScope && "Invalid Scope.");
|
||||||
|
|
||||||
|
@ -8579,7 +8577,7 @@ Decl *Sema::ActOnUsingDeclaration(Scope *S,
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
// Warn about access declarations.
|
// Warn about access declarations.
|
||||||
if (!HasUsingKeyword) {
|
if (UsingLoc.isInvalid()) {
|
||||||
Diag(Name.getLocStart(),
|
Diag(Name.getLocStart(),
|
||||||
getLangOpts().CPlusPlus11 ? diag::err_access_decl
|
getLangOpts().CPlusPlus11 ? diag::err_access_decl
|
||||||
: diag::warn_access_decl_deprecated)
|
: diag::warn_access_decl_deprecated)
|
||||||
|
@ -8593,7 +8591,7 @@ Decl *Sema::ActOnUsingDeclaration(Scope *S,
|
||||||
NamedDecl *UD = BuildUsingDeclaration(S, AS, UsingLoc, SS,
|
NamedDecl *UD = BuildUsingDeclaration(S, AS, UsingLoc, SS,
|
||||||
TargetNameInfo, AttrList,
|
TargetNameInfo, AttrList,
|
||||||
/* IsInstantiation */ false,
|
/* IsInstantiation */ false,
|
||||||
HasTypenameKeyword, TypenameLoc);
|
TypenameLoc.isValid(), TypenameLoc);
|
||||||
if (UD)
|
if (UD)
|
||||||
PushOnScopeChains(UD, S, /*AddToContext*/ false);
|
PushOnScopeChains(UD, S, /*AddToContext*/ false);
|
||||||
|
|
||||||
|
|
|
@ -136,5 +136,5 @@ template<int ...N> void NoMissingSemicolonHereEither(struct S
|
||||||
... [N]);
|
... [N]);
|
||||||
|
|
||||||
// This must be at the end of the file; we used to look ahead past the EOF token here.
|
// This must be at the end of the file; we used to look ahead past the EOF token here.
|
||||||
// expected-error@+1 {{expected unqualified-id}}
|
// expected-error@+1 {{expected unqualified-id}} expected-error@+1{{expected ';'}}
|
||||||
using
|
using
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
// RUN: %clang_cc1 -std=c++1z -verify %s
|
||||||
|
|
||||||
|
namespace A {
|
||||||
|
int m, n;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace B {
|
||||||
|
using A::m, A::n, A::n;
|
||||||
|
int q = m + n;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct X {
|
||||||
|
int x1, x2, y, z; // expected-note {{conflicting}}
|
||||||
|
};
|
||||||
|
struct Y {
|
||||||
|
int x1, x2, y, z; // expected-note {{target}}
|
||||||
|
};
|
||||||
|
struct Z : X, Y {
|
||||||
|
using X::x1,
|
||||||
|
blah::blah, // expected-error {{undeclared}}
|
||||||
|
X::x2, // expected-note {{previous}}
|
||||||
|
Y::y,
|
||||||
|
X::x2, // expected-error {{redeclaration}}
|
||||||
|
X::z,
|
||||||
|
Y::z; // expected-error {{conflicts with}}
|
||||||
|
};
|
||||||
|
int X::*px1 = &Z::x1;
|
||||||
|
int X::*px2 = &Z::x2;
|
||||||
|
int Y::*py = &Z::y;
|
||||||
|
int X::*pz = &Z::z;
|
Loading…
Reference in New Issue