[c++1z] P0195R2: Allow multiple using-declarators in a single using-declaration.

llvm-svn: 289905
This commit is contained in:
Richard Smith 2016-12-16 00:58:48 +00:00
parent 53f14c78b5
commit 6f1daa4660
9 changed files with 346 additions and 177 deletions

View File

@ -741,6 +741,15 @@ def err_alias_declaration_not_identifier : Error<
def err_alias_declaration_specialization : Error<
"%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
def ext_override_control_keyword : ExtWarn<
"'%0' keyword is a C++11 extension">, InGroup<CXX11>;

View File

@ -1261,6 +1261,11 @@ private:
ParsedAttributesWithRange(AttributeFactory &factory)
: ParsedAttributes(factory) {}
void clear() {
ParsedAttributes::clear();
Range = SourceRange();
}
SourceRange Range;
};
@ -2418,21 +2423,41 @@ private:
BalancedDelimiterTracker &Tracker);
Decl *ParseLinkage(ParsingDeclSpec &DS, unsigned Context);
Decl *ParseExportDeclaration();
Decl *ParseUsingDirectiveOrDeclaration(unsigned Context,
const ParsedTemplateInfo &TemplateInfo,
SourceLocation &DeclEnd,
ParsedAttributesWithRange &attrs,
Decl **OwnedType = nullptr);
DeclGroupPtrTy ParseUsingDirectiveOrDeclaration(
unsigned Context, const ParsedTemplateInfo &TemplateInfo,
SourceLocation &DeclEnd, ParsedAttributesWithRange &attrs);
Decl *ParseUsingDirective(unsigned Context,
SourceLocation UsingLoc,
SourceLocation &DeclEnd,
ParsedAttributes &attrs);
Decl *ParseUsingDeclaration(unsigned Context,
const ParsedTemplateInfo &TemplateInfo,
SourceLocation UsingLoc,
SourceLocation &DeclEnd,
AccessSpecifier AS = AS_none,
Decl **OwnedType = nullptr);
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,
SourceLocation UsingLoc,
SourceLocation &DeclEnd,
AccessSpecifier AS = AS_none);
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 *ParseNamespaceAlias(SourceLocation NamespaceLoc,
SourceLocation AliasLoc, IdentifierInfo *Alias,

View File

@ -4341,12 +4341,10 @@ public:
Decl *ActOnUsingDeclaration(Scope *CurScope,
AccessSpecifier AS,
bool HasUsingKeyword,
SourceLocation UsingLoc,
CXXScopeSpec &SS,
UnqualifiedId &Name,
AttributeList *AttrList,
bool HasTypenameKeyword,
SourceLocation TypenameLoc);
Decl *ActOnAliasDeclaration(Scope *CurScope,
AccessSpecifier AS,

View File

@ -1506,7 +1506,6 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(unsigned Context,
ObjCDeclContextSwitch ObjCDC(*this);
Decl *SingleDecl = nullptr;
Decl *OwnedType = nullptr;
switch (Tok.getKind()) {
case tok::kw_template:
case tok::kw_export:
@ -1526,9 +1525,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(unsigned Context,
ProhibitAttributes(attrs);
return ParseNamespace(Context, DeclEnd);
case tok::kw_using:
SingleDecl = ParseUsingDirectiveOrDeclaration(Context, ParsedTemplateInfo(),
DeclEnd, attrs, &OwnedType);
break;
return ParseUsingDirectiveOrDeclaration(Context, ParsedTemplateInfo(),
DeclEnd, attrs);
case tok::kw_static_assert:
case tok::kw__Static_assert:
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
// single decl, convert it now. Alias declarations can also declare a type;
// include that too if it is present.
return Actions.ConvertDeclToDeclGroup(SingleDecl, OwnedType);
// single decl, convert it now.
return Actions.ConvertDeclToDeclGroup(SingleDecl);
}
/// simple-declaration: [C99 6.7: declaration] [C++ 7p1: dcl.dcl]

View File

@ -421,11 +421,11 @@ Decl *Parser::ParseExportDeclaration() {
/// ParseUsingDirectiveOrDeclaration - Parse C++ using using-declaration or
/// using-directive. Assumes that current token is 'using'.
Decl *Parser::ParseUsingDirectiveOrDeclaration(unsigned Context,
Parser::DeclGroupPtrTy
Parser::ParseUsingDirectiveOrDeclaration(unsigned Context,
const ParsedTemplateInfo &TemplateInfo,
SourceLocation &DeclEnd,
ParsedAttributesWithRange &attrs,
Decl **OwnedType) {
SourceLocation &DeclEnd,
ParsedAttributesWithRange &attrs) {
assert(Tok.is(tok::kw_using) && "Not using token");
ObjCDeclContextSwitch ObjCDC(*this);
@ -447,7 +447,8 @@ Decl *Parser::ParseUsingDirectiveOrDeclaration(unsigned Context,
<< 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.
@ -456,7 +457,7 @@ Decl *Parser::ParseUsingDirectiveOrDeclaration(unsigned Context,
ProhibitAttributes(attrs);
return ParseUsingDeclaration(Context, TemplateInfo, UsingLoc, DeclEnd,
AS_none, OwnedType);
AS_none);
}
/// ParseUsingDirective - Parse C++ using-directive, assumes
@ -522,58 +523,31 @@ Decl *Parser::ParseUsingDirective(unsigned Context,
IdentLoc, NamespcName, attrs.getList());
}
/// ParseUsingDeclaration - Parse C++ using-declaration or alias-declaration.
/// Assumes that 'using' was already seen.
/// Parse a using-declarator (or the identifier in a C++11 alias-declaration).
///
/// using-declaration: [C++ 7.3.p3: namespace.udecl]
/// 'using' 'typename'[opt] ::[opt] nested-name-specifier
/// unqualified-id
/// 'using' :: unqualified-id
/// using-declarator:
/// 'typename'[opt] nested-name-specifier unqualified-id
///
/// alias-declaration: C++11 [dcl.dcl]p1
/// 'using' identifier attribute-specifier-seq[opt] = type-id ;
///
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);
bool Parser::ParseUsingDeclarator(unsigned Context, UsingDeclarator &D) {
D.clear();
// Ignore optional 'typename'.
// FIXME: This is wrong; we should parse this as a typename-specifier.
if (TryConsumeToken(tok::kw_typename, TypenameLoc))
HasTypenameKeyword = true;
TryConsumeToken(tok::kw_typename, D.TypenameLoc);
if (Tok.is(tok::kw___super)) {
Diag(Tok.getLocation(), diag::err_super_in_using_declaration);
SkipUntil(tok::semi);
return nullptr;
return true;
}
// Parse nested-name-specifier.
IdentifierInfo *LastII = nullptr;
ParseOptionalCXXScopeSpecifier(SS, nullptr, /*EnteringContext=*/false,
ParseOptionalCXXScopeSpecifier(D.SS, nullptr, /*EnteringContext=*/false,
/*MayBePseudoDtor=*/nullptr,
/*IsTypename=*/false,
/*LastII=*/&LastII);
// Check nested-name specifier.
if (SS.isInvalid()) {
SkipUntil(tok::semi);
return nullptr;
}
SourceLocation TemplateKWLoc;
UnqualifiedId Name;
if (D.SS.isInvalid())
return true;
// Parse the unqualified-id. We allow parsing of both constructor and
// destructor names and allow the action module to diagnose any semantic
@ -587,31 +561,68 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
// constructor.
if (getLangOpts().CPlusPlus11 && Context == Declarator::MemberContext &&
Tok.is(tok::identifier) && NextToken().is(tok::semi) &&
SS.isNotEmpty() && LastII == Tok.getIdentifierInfo() &&
!SS.getScopeRep()->getAsNamespace() &&
!SS.getScopeRep()->getAsNamespaceAlias()) {
D.SS.isNotEmpty() && LastII == Tok.getIdentifierInfo() &&
!D.SS.getScopeRep()->getAsNamespace() &&
!D.SS.getScopeRep()->getAsNamespaceAlias()) {
SourceLocation IdLoc = ConsumeToken();
ParsedType Type = Actions.getInheritingConstructorName(SS, IdLoc, *LastII);
Name.setConstructorName(Type, IdLoc, IdLoc);
} else if (ParseUnqualifiedId(
SS, /*EnteringContext=*/false,
/*AllowDestructorName=*/true,
/*AllowConstructorName=*/!(Tok.is(tok::identifier) &&
NextToken().is(tok::equal)),
nullptr, TemplateKWLoc, Name)) {
SkipUntil(tok::semi);
return nullptr;
ParsedType Type =
Actions.getInheritingConstructorName(D.SS, IdLoc, *LastII);
D.Name.setConstructorName(Type, IdLoc, IdLoc);
} else {
if (ParseUnqualifiedId(
D.SS, /*EnteringContext=*/false,
/*AllowDestructorName=*/true,
/*AllowConstructorName=*/!(Tok.is(tok::identifier) &&
NextToken().is(tok::equal)),
nullptr, D.TemplateKWLoc, D.Name))
return true;
}
// 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);
MaybeParseGNUAttributes(Attrs);
MaybeParseCXX11Attributes(Attrs);
// Maybe this is an alias-declaration.
TypeResult TypeAlias;
bool IsAliasDecl = Tok.is(tok::equal);
Decl *DeclFromDeclSpec = nullptr;
if (IsAliasDecl) {
if (Tok.is(tok::equal)) {
if (InvalidDeclarator) {
SkipUntil(tok::semi);
return nullptr;
}
// If we had any misplaced attributes from earlier, this is where they
// should have been written.
if (MisplacedAttrs.Range.isValid()) {
@ -623,76 +634,21 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
Attrs.takeAllFrom(MisplacedAttrs);
}
ConsumeToken();
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 &&
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
// are.
ProhibitAttributes(MisplacedAttrs);
ProhibitAttributes(Attrs);
// Parse (optional) attributes (most likely GNU strong-using extension).
MaybeParseGNUAttributes(Attrs);
Decl *DeclFromDeclSpec = nullptr;
Decl *AD = ParseAliasDeclarationAfterDeclarator(
TemplateInfo, UsingLoc, D, DeclEnd, AS, Attrs, &DeclFromDeclSpec);
return Actions.ConvertDeclToDeclGroup(AD, DeclFromDeclSpec);
}
// Eat ';'.
DeclEnd = Tok.getLocation();
if (ExpectAndConsume(tok::semi, diag::err_expected_after,
!Attrs.empty() ? "attributes list"
: IsAliasDecl ? "alias declaration"
: "using declaration"))
SkipUntil(tok::semi);
// C++11 attributes are not allowed on a using-declaration, but GNU ones
// are.
ProhibitAttributes(MisplacedAttrs);
ProhibitAttributes(Attrs);
// Diagnose an attempt to declare a templated using-declaration.
// In C++11, alias-declarations can be templates:
// template <...> using id = type;
if (TemplateInfo.Kind && !IsAliasDecl) {
if (TemplateInfo.Kind) {
SourceRange R = TemplateInfo.getSourceRange();
Diag(UsingLoc, diag::err_templated_using_directive_declaration)
<< 1 /* declaration */ << R << FixItHint::CreateRemoval(R);
@ -703,29 +659,184 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
return nullptr;
}
// "typename" keyword is allowed for identifiers only,
// because it may be a type definition.
if (HasTypenameKeyword && Name.getKind() != UnqualifiedId::IK_Identifier) {
Diag(Name.getSourceRange().getBegin(), diag::err_typename_identifiers_only)
<< FixItHint::CreateRemoval(SourceRange(TypenameLoc));
// Proceed parsing, but reset the HasTypenameKeyword flag.
HasTypenameKeyword = false;
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,
// because it may be a type definition.
if (D.TypenameLoc.isValid() &&
D.Name.getKind() != UnqualifiedId::IK_Identifier) {
Diag(D.Name.getSourceRange().getBegin(),
diag::err_typename_identifiers_only)
<< FixItHint::CreateRemoval(SourceRange(D.TypenameLoc));
// Proceed parsing, but discard the typename keyword.
D.TypenameLoc = SourceLocation();
}
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 (IsAliasDecl) {
TemplateParameterLists *TemplateParams = TemplateInfo.TemplateParams;
MultiTemplateParamsArg TemplateParamsArg(
TemplateParams ? TemplateParams->data() : nullptr,
TemplateParams ? TemplateParams->size() : 0);
return Actions.ActOnAliasDeclaration(getCurScope(), AS, TemplateParamsArg,
UsingLoc, Name, Attrs.getList(),
TypeAlias, DeclFromDeclSpec);
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;
}
return Actions.ActOnUsingDeclaration(getCurScope(), AS,
/* HasUsingKeyword */ true, UsingLoc,
SS, Name, Attrs.getList(),
HasTypenameKeyword, TypenameLoc);
// '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;
MultiTemplateParamsArg TemplateParamsArg(
TemplateParams ? TemplateParams->data() : nullptr,
TemplateParams ? TemplateParams->size() : 0);
return Actions.ActOnAliasDeclaration(getCurScope(), AS, TemplateParamsArg,
UsingLoc, D.Name, Attrs.getList(),
TypeAlias, DeclFromDeclSpec);
}
/// ParseStaticAssertDeclaration - Parse C++0x or C11 static_assert-declaration.
@ -2376,10 +2487,8 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
}
return DeclGroupPtrTy::make(DeclGroupRef(Actions.ActOnUsingDeclaration(
getCurScope(), AS,
/* HasUsingKeyword */ false, SourceLocation(), SS, Name,
/* AttrList */ nullptr,
/* HasTypenameKeyword */ false, SourceLocation())));
getCurScope(), AS, /*UsingLoc*/SourceLocation(), SS, Name,
/*AttrList*/nullptr, /*TypenameLoc*/SourceLocation())));
}
}
@ -2434,8 +2543,8 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
}
SourceLocation DeclEnd;
// Otherwise, it must be a using-declaration or an alias-declaration.
return DeclGroupPtrTy::make(DeclGroupRef(ParseUsingDeclaration(
Declarator::MemberContext, TemplateInfo, UsingLoc, DeclEnd, AS)));
return ParseUsingDeclaration(Declarator::MemberContext, TemplateInfo,
UsingLoc, DeclEnd, AS);
}
// Hold late-parsed attributes so we can attach a Decl to them later.

View File

@ -196,9 +196,12 @@ Parser::ParseSingleDeclarationAfterTemplate(
ParsedAttributesWithRange prefixAttrs(AttrFactory);
MaybeParseCXX11Attributes(prefixAttrs);
if (Tok.is(tok::kw_using))
return ParseUsingDirectiveOrDeclaration(Context, TemplateInfo, DeclEnd,
prefixAttrs);
if (Tok.is(tok::kw_using)) {
// FIXME: We should return the DeclGroup to the caller.
ParseUsingDirectiveOrDeclaration(Context, TemplateInfo, DeclEnd,
prefixAttrs);
return nullptr;
}
// Parse the declaration specifiers, stealing any diagnostics from
// the template parameters.

View File

@ -8532,12 +8532,10 @@ void Sema::PushUsingDirective(Scope *S, UsingDirectiveDecl *UDir) {
Decl *Sema::ActOnUsingDeclaration(Scope *S,
AccessSpecifier AS,
bool HasUsingKeyword,
SourceLocation UsingLoc,
CXXScopeSpec &SS,
UnqualifiedId &Name,
AttributeList *AttrList,
bool HasTypenameKeyword,
SourceLocation TypenameLoc) {
assert(S->getFlags() & Scope::DeclScope && "Invalid Scope.");
@ -8579,7 +8577,7 @@ Decl *Sema::ActOnUsingDeclaration(Scope *S,
return nullptr;
// Warn about access declarations.
if (!HasUsingKeyword) {
if (UsingLoc.isInvalid()) {
Diag(Name.getLocStart(),
getLangOpts().CPlusPlus11 ? diag::err_access_decl
: diag::warn_access_decl_deprecated)
@ -8593,7 +8591,7 @@ Decl *Sema::ActOnUsingDeclaration(Scope *S,
NamedDecl *UD = BuildUsingDeclaration(S, AS, UsingLoc, SS,
TargetNameInfo, AttrList,
/* IsInstantiation */ false,
HasTypenameKeyword, TypenameLoc);
TypenameLoc.isValid(), TypenameLoc);
if (UD)
PushOnScopeChains(UD, S, /*AddToContext*/ false);

View File

@ -136,5 +136,5 @@ template<int ...N> void NoMissingSemicolonHereEither(struct S
... [N]);
// 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

View File

@ -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;