Support decltype in nested-name-specifiers.
llvm-svn: 145785
This commit is contained in:
parent
80381f6cbf
commit
15a430a368
|
@ -36,8 +36,9 @@ class LangOptions;
|
|||
/// namespaces. For example, "foo::" in "foo::x" is a nested name
|
||||
/// specifier. Nested name specifiers are made up of a sequence of
|
||||
/// specifiers, each of which can be a namespace, type, identifier
|
||||
/// (for dependent names), or the global specifier ('::', must be the
|
||||
/// first specifier).
|
||||
/// (for dependent names), decltype specifier, or the global specifier ('::').
|
||||
/// The last two specifiers can only appear at the start of a
|
||||
/// nested-namespace-specifier.
|
||||
class NestedNameSpecifier : public llvm::FoldingSetNode {
|
||||
|
||||
/// \brief Enumeration describing
|
||||
|
|
|
@ -3993,6 +3993,8 @@ def err_typecheck_deleted_function : Error<
|
|||
"conversion function from %0 to %1 invokes a deleted function">;
|
||||
|
||||
def err_expected_class_or_namespace : Error<"expected a class or namespace">;
|
||||
def err_expected_class : Error<"%0 is not a class%select{ or namespace|, "
|
||||
"namespace, or scoped enumeration}1">;
|
||||
def err_missing_qualified_for_redecl : Error<
|
||||
"must qualify the name %0 to declare %q1 in this scope">;
|
||||
def err_invalid_declarator_scope : Error<
|
||||
|
|
|
@ -560,6 +560,8 @@ ANNOTATION(template_id) // annotation for a C++ template-id that names a
|
|||
// function template specialization (not a type),
|
||||
// e.g., "std::swap<int>"
|
||||
ANNOTATION(primary_expr) // annotation for a primary expression
|
||||
ANNOTATION(decltype) // annotation for a decltype expression,
|
||||
// e.g., "decltype(foo.bar())"
|
||||
|
||||
// Annotation for #pragma unused(...)
|
||||
// For each argument inside the parentheses the pragma handler will produce
|
||||
|
|
|
@ -1901,7 +1901,10 @@ private:
|
|||
|
||||
|
||||
void ParseTypeofSpecifier(DeclSpec &DS);
|
||||
void ParseDecltypeSpecifier(DeclSpec &DS);
|
||||
SourceLocation ParseDecltypeSpecifier(DeclSpec &DS);
|
||||
void AnnotateExistingDecltypeSpecifier(const DeclSpec &DS,
|
||||
SourceLocation StartLoc,
|
||||
SourceLocation EndLoc);
|
||||
void ParseUnderlyingTypeSpecifier(DeclSpec &DS);
|
||||
void ParseAtomicSpecifier(DeclSpec &DS);
|
||||
|
||||
|
|
|
@ -3326,6 +3326,10 @@ public:
|
|||
bool EnteringContext,
|
||||
CXXScopeSpec &SS);
|
||||
|
||||
bool ActOnCXXNestedNameSpecifierDecltype(CXXScopeSpec &SS,
|
||||
const DeclSpec &DS,
|
||||
SourceLocation ColonColonLoc);
|
||||
|
||||
bool IsInvalidUnlessNestedName(Scope *S, CXXScopeSpec &SS,
|
||||
IdentifierInfo &Identifier,
|
||||
SourceLocation IdentifierLoc,
|
||||
|
|
|
@ -1889,6 +1889,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
|
|||
goto DoneWithDeclSpec;
|
||||
|
||||
// typedef-name
|
||||
case tok::kw_decltype:
|
||||
case tok::identifier: {
|
||||
// In C++, check to see if this is a scope specifier like foo::bar::, if
|
||||
// so handle it as such. This is important for ctor parsing.
|
||||
|
@ -2248,7 +2249,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
|
|||
ParseTypeofSpecifier(DS);
|
||||
continue;
|
||||
|
||||
case tok::kw_decltype:
|
||||
case tok::annot_decltype:
|
||||
ParseDecltypeSpecifier(DS);
|
||||
continue;
|
||||
|
||||
|
@ -2370,6 +2371,7 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid,
|
|||
if (TryAltiVecToken(DS, Loc, PrevSpec, DiagID, isInvalid))
|
||||
break;
|
||||
// Fall through.
|
||||
case tok::kw_decltype:
|
||||
case tok::kw_typename: // typename foo::bar
|
||||
// Annotate typenames and C++ scope specifiers. If we get one, just
|
||||
// recurse to handle whatever we get.
|
||||
|
@ -2532,7 +2534,7 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid,
|
|||
return true;
|
||||
|
||||
// C++0x decltype support.
|
||||
case tok::kw_decltype:
|
||||
case tok::annot_decltype:
|
||||
ParseDecltypeSpecifier(DS);
|
||||
return true;
|
||||
|
||||
|
@ -3346,6 +3348,7 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
|
|||
if (TryAltiVecVectorToken())
|
||||
return true;
|
||||
// Fall through.
|
||||
case tok::kw_decltype: // decltype(T())::type
|
||||
case tok::kw_typename: // typename T::type
|
||||
// Annotate typenames and C++ scope specifiers. If we get one, just
|
||||
// recurse to handle whatever we get.
|
||||
|
@ -3441,7 +3444,7 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
|
|||
return true;
|
||||
|
||||
// C++0x decltype.
|
||||
case tok::kw_decltype:
|
||||
case tok::annot_decltype:
|
||||
return true;
|
||||
|
||||
// C1x _Atomic()
|
||||
|
@ -3968,6 +3971,10 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
|
|||
|
||||
while (1) {
|
||||
if (Tok.is(tok::l_paren)) {
|
||||
// Enter function-declaration scope, limiting any declarators to the
|
||||
// function prototype scope, including parameter declarators.
|
||||
ParseScope PrototypeScope(this,
|
||||
Scope::FunctionPrototypeScope|Scope::DeclScope);
|
||||
// The paren may be part of a C++ direct initializer, eg. "int x(1);".
|
||||
// In such a case, check if we actually have a function declarator; if it
|
||||
// is not, the declarator has been fully parsed.
|
||||
|
@ -3982,13 +3989,14 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
|
|||
BalancedDelimiterTracker T(*this, tok::l_paren);
|
||||
T.consumeOpen();
|
||||
ParseFunctionDeclarator(D, attrs, T);
|
||||
PrototypeScope.Exit();
|
||||
} else if (Tok.is(tok::l_square)) {
|
||||
ParseBracketDeclarator(D);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// ParseParenDeclarator - We parsed the declarator D up to a paren. This is
|
||||
/// only called before the identifier, so these are most likely just grouping
|
||||
|
@ -4084,7 +4092,12 @@ void Parser::ParseParenDeclarator(Declarator &D) {
|
|||
// ParseFunctionDeclarator to handle of argument list.
|
||||
D.SetIdentifier(0, Tok.getLocation());
|
||||
|
||||
// Enter function-declaration scope, limiting any declarators to the
|
||||
// function prototype scope, including parameter declarators.
|
||||
ParseScope PrototypeScope(this,
|
||||
Scope::FunctionPrototypeScope|Scope::DeclScope);
|
||||
ParseFunctionDeclarator(D, attrs, T, RequiresArg);
|
||||
PrototypeScope.Exit();
|
||||
}
|
||||
|
||||
/// ParseFunctionDeclarator - We are after the identifier and have parsed the
|
||||
|
@ -4109,6 +4122,8 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
|
|||
ParsedAttributes &attrs,
|
||||
BalancedDelimiterTracker &Tracker,
|
||||
bool RequiresArg) {
|
||||
assert(getCurScope()->isFunctionPrototypeScope() &&
|
||||
"Should call from a Function scope");
|
||||
// lparen is already consumed!
|
||||
assert(D.isPastIdentifier() && "Should not call before identifier!");
|
||||
|
||||
|
@ -4142,11 +4157,6 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
|
|||
Tracker.consumeClose();
|
||||
EndLoc = Tracker.getCloseLocation();
|
||||
} else {
|
||||
// Enter function-declaration scope, limiting any declarators to the
|
||||
// function prototype scope, including parameter declarators.
|
||||
ParseScope PrototypeScope(this,
|
||||
Scope::FunctionPrototypeScope|Scope::DeclScope);
|
||||
|
||||
if (Tok.isNot(tok::r_paren))
|
||||
ParseParameterDeclarationClause(D, attrs, ParamInfo, EllipsisLoc);
|
||||
else if (RequiresArg)
|
||||
|
@ -4197,9 +4207,6 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
|
|||
EndLoc = Range.getEnd();
|
||||
}
|
||||
}
|
||||
|
||||
// Leave prototype scope.
|
||||
PrototypeScope.Exit();
|
||||
}
|
||||
|
||||
// Remember that we parsed a function type, and remember the attributes.
|
||||
|
|
|
@ -632,39 +632,85 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){
|
|||
///
|
||||
/// 'decltype' ( expression )
|
||||
///
|
||||
void Parser::ParseDecltypeSpecifier(DeclSpec &DS) {
|
||||
assert(Tok.is(tok::kw_decltype) && "Not a decltype specifier");
|
||||
SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) {
|
||||
assert((Tok.is(tok::kw_decltype) || Tok.is(tok::annot_decltype))
|
||||
&& "Not a decltype specifier");
|
||||
|
||||
|
||||
SourceLocation StartLoc = ConsumeToken();
|
||||
BalancedDelimiterTracker T(*this, tok::l_paren);
|
||||
if (T.expectAndConsume(diag::err_expected_lparen_after,
|
||||
"decltype", tok::r_paren)) {
|
||||
return;
|
||||
ExprResult Result;
|
||||
SourceLocation StartLoc = Tok.getLocation();
|
||||
SourceLocation EndLoc;
|
||||
|
||||
if (Tok.is(tok::annot_decltype)) {
|
||||
Result = getExprAnnotation(Tok);
|
||||
EndLoc = Tok.getAnnotationEndLoc();
|
||||
ConsumeToken();
|
||||
if (Result.isInvalid()) {
|
||||
DS.SetTypeSpecError();
|
||||
return EndLoc;
|
||||
}
|
||||
} else {
|
||||
ConsumeToken();
|
||||
|
||||
BalancedDelimiterTracker T(*this, tok::l_paren);
|
||||
if (T.expectAndConsume(diag::err_expected_lparen_after,
|
||||
"decltype", tok::r_paren)) {
|
||||
DS.SetTypeSpecError();
|
||||
return T.getOpenLocation() == Tok.getLocation() ?
|
||||
StartLoc : T.getOpenLocation();
|
||||
}
|
||||
|
||||
// Parse the expression
|
||||
|
||||
// C++0x [dcl.type.simple]p4:
|
||||
// The operand of the decltype specifier is an unevaluated operand.
|
||||
EnterExpressionEvaluationContext Unevaluated(Actions,
|
||||
Sema::Unevaluated);
|
||||
Result = ParseExpression();
|
||||
if (Result.isInvalid()) {
|
||||
SkipUntil(tok::r_paren, true, true);
|
||||
DS.SetTypeSpecError();
|
||||
return Tok.is(tok::eof) ? Tok.getLocation() : ConsumeParen();
|
||||
}
|
||||
|
||||
// Match the ')'
|
||||
T.consumeClose();
|
||||
if (T.getCloseLocation().isInvalid()) {
|
||||
DS.SetTypeSpecError();
|
||||
// FIXME: this should return the location of the last token
|
||||
// that was consumed (by "consumeClose()")
|
||||
return T.getCloseLocation();
|
||||
}
|
||||
|
||||
EndLoc = T.getCloseLocation();
|
||||
}
|
||||
|
||||
// Parse the expression
|
||||
|
||||
// C++0x [dcl.type.simple]p4:
|
||||
// The operand of the decltype specifier is an unevaluated operand.
|
||||
EnterExpressionEvaluationContext Unevaluated(Actions,
|
||||
Sema::Unevaluated);
|
||||
ExprResult Result = ParseExpression();
|
||||
if (Result.isInvalid()) {
|
||||
SkipUntil(tok::r_paren);
|
||||
return;
|
||||
}
|
||||
|
||||
// Match the ')'
|
||||
T.consumeClose();
|
||||
if (T.getCloseLocation().isInvalid())
|
||||
return;
|
||||
|
||||
const char *PrevSpec = 0;
|
||||
unsigned DiagID;
|
||||
// Check for duplicate type specifiers (e.g. "int decltype(a)").
|
||||
if (DS.SetTypeSpecType(DeclSpec::TST_decltype, StartLoc, PrevSpec,
|
||||
DiagID, Result.release()))
|
||||
DiagID, Result.release())) {
|
||||
Diag(StartLoc, DiagID) << PrevSpec;
|
||||
DS.SetTypeSpecError();
|
||||
}
|
||||
return EndLoc;
|
||||
}
|
||||
|
||||
void Parser::AnnotateExistingDecltypeSpecifier(const DeclSpec& DS,
|
||||
SourceLocation StartLoc,
|
||||
SourceLocation EndLoc) {
|
||||
// make sure we have a token we can turn into an annotation token
|
||||
if (PP.isBacktrackEnabled())
|
||||
PP.RevertCachedTokens(1);
|
||||
else
|
||||
PP.EnterToken(Tok);
|
||||
|
||||
Tok.setKind(tok::annot_decltype);
|
||||
setExprAnnotation(Tok, DS.getTypeSpecType() == TST_decltype ?
|
||||
DS.getRepAsExpr() : ExprResult());
|
||||
Tok.setAnnotationEndLoc(EndLoc);
|
||||
Tok.setLocation(StartLoc);
|
||||
PP.AnnotateCachedTokens(Tok);
|
||||
}
|
||||
|
||||
void Parser::ParseUnderlyingTypeSpecifier(DeclSpec &DS) {
|
||||
|
@ -727,14 +773,16 @@ Parser::TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc,
|
|||
BaseLoc = Tok.getLocation();
|
||||
|
||||
// Parse decltype-specifier
|
||||
if (Tok.is(tok::kw_decltype)) {
|
||||
// tok == kw_decltype is just error recovery, it can only happen when SS
|
||||
// isn't empty
|
||||
if (Tok.is(tok::kw_decltype) || Tok.is(tok::annot_decltype)) {
|
||||
if (SS.isNotEmpty())
|
||||
Diag(SS.getBeginLoc(), diag::err_unexpected_scope_on_base_decltype)
|
||||
<< FixItHint::CreateRemoval(SS.getRange());
|
||||
// Fake up a Declarator to use with ActOnTypeName.
|
||||
DeclSpec DS(AttrFactory);
|
||||
|
||||
ParseDecltypeSpecifier(DS);
|
||||
ParseDecltypeSpecifier(DS);
|
||||
EndLocation = DS.getSourceRange().getEnd();
|
||||
|
||||
Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
|
||||
|
|
|
@ -664,6 +664,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
|
|||
ConsumeToken();
|
||||
break;
|
||||
|
||||
case tok::kw_decltype:
|
||||
case tok::identifier: { // primary-expression: identifier
|
||||
// unqualified-id: identifier
|
||||
// constant: enumeration-constant
|
||||
|
|
|
@ -168,6 +168,22 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
|
|||
*MayBePseudoDestructor = false;
|
||||
}
|
||||
|
||||
if (Tok.is(tok::kw_decltype) || Tok.is(tok::annot_decltype)) {
|
||||
DeclSpec DS(AttrFactory);
|
||||
SourceLocation DeclLoc = Tok.getLocation();
|
||||
SourceLocation EndLoc = ParseDecltypeSpecifier(DS);
|
||||
if (Tok.isNot(tok::coloncolon)) {
|
||||
AnnotateExistingDecltypeSpecifier(DS, DeclLoc, EndLoc);
|
||||
return false;
|
||||
}
|
||||
|
||||
SourceLocation CCLoc = ConsumeToken();
|
||||
if (Actions.ActOnCXXNestedNameSpecifierDecltype(SS, DS, CCLoc))
|
||||
SS.SetInvalid(SourceRange(DeclLoc, CCLoc));
|
||||
|
||||
HasScopeSpecifier = true;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
if (HasScopeSpecifier) {
|
||||
// C++ [basic.lookup.classref]p5:
|
||||
|
|
|
@ -706,7 +706,6 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) {
|
|||
case tok::kw_wchar_t:
|
||||
case tok::kw_char16_t:
|
||||
case tok::kw_char32_t:
|
||||
case tok::kw_decltype:
|
||||
case tok::kw___underlying_type:
|
||||
case tok::kw_thread_local:
|
||||
case tok::kw__Decimal32:
|
||||
|
@ -848,13 +847,14 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() {
|
|||
if (Next.is(tok::kw_new) || // ::new
|
||||
Next.is(tok::kw_delete)) // ::delete
|
||||
return TPResult::False();
|
||||
|
||||
}
|
||||
// Fall through.
|
||||
case tok::kw_decltype:
|
||||
// Annotate typenames and C++ scope specifiers. If we get one, just
|
||||
// recurse to handle whatever we get.
|
||||
if (TryAnnotateTypeOrScopeToken())
|
||||
return TPResult::Error();
|
||||
return isCXXDeclarationSpecifier();
|
||||
}
|
||||
|
||||
// decl-specifier:
|
||||
// storage-class-specifier
|
||||
|
@ -1030,7 +1030,7 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() {
|
|||
}
|
||||
|
||||
// C++0x decltype support.
|
||||
case tok::kw_decltype:
|
||||
case tok::annot_decltype:
|
||||
return TPResult::True();
|
||||
|
||||
// C++0x type traits support
|
||||
|
|
|
@ -1202,8 +1202,8 @@ TemplateIdAnnotation *Parser::takeTemplateIdAnnotation(const Token &tok) {
|
|||
/// as the current tokens, so only call it in contexts where these are invalid.
|
||||
bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext, bool NeedType) {
|
||||
assert((Tok.is(tok::identifier) || Tok.is(tok::coloncolon)
|
||||
|| Tok.is(tok::kw_typename) || Tok.is(tok::annot_cxxscope)) &&
|
||||
"Cannot be a type or scope token!");
|
||||
|| Tok.is(tok::kw_typename) || Tok.is(tok::annot_cxxscope)
|
||||
|| Tok.is(tok::kw_decltype)) && "Cannot be a type or scope token!");
|
||||
|
||||
if (Tok.is(tok::kw_typename)) {
|
||||
// Parse a C++ typename-specifier, e.g., "typename T::type".
|
||||
|
@ -1382,8 +1382,8 @@ bool Parser::TryAnnotateCXXScopeToken(bool EnteringContext) {
|
|||
assert(getLang().CPlusPlus &&
|
||||
"Call sites of this function should be guarded by checking for C++");
|
||||
assert((Tok.is(tok::identifier) || Tok.is(tok::coloncolon) ||
|
||||
(Tok.is(tok::annot_template_id) && NextToken().is(tok::coloncolon)))&&
|
||||
"Cannot be a type or scope token!");
|
||||
(Tok.is(tok::annot_template_id) && NextToken().is(tok::coloncolon)) ||
|
||||
Tok.is(tok::kw_decltype)) && "Cannot be a type or scope token!");
|
||||
|
||||
CXXScopeSpec SS;
|
||||
if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), EnteringContext))
|
||||
|
|
|
@ -676,6 +676,29 @@ bool Sema::ActOnCXXNestedNameSpecifier(Scope *S,
|
|||
/*ScopeLookupResult=*/0, false);
|
||||
}
|
||||
|
||||
bool Sema::ActOnCXXNestedNameSpecifierDecltype(CXXScopeSpec &SS,
|
||||
const DeclSpec &DS,
|
||||
SourceLocation ColonColonLoc) {
|
||||
if (SS.isInvalid() || DS.getTypeSpecType() == DeclSpec::TST_error)
|
||||
return true;
|
||||
|
||||
assert(DS.getTypeSpecType() == DeclSpec::TST_decltype);
|
||||
|
||||
QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc());
|
||||
if (!T->isDependentType() && !T->getAs<TagType>()) {
|
||||
Diag(DS.getTypeSpecTypeLoc(), diag::err_expected_class)
|
||||
<< T << getLangOptions().CPlusPlus;
|
||||
return true;
|
||||
}
|
||||
|
||||
TypeLocBuilder TLB;
|
||||
DecltypeTypeLoc DecltypeTL = TLB.push<DecltypeTypeLoc>(T);
|
||||
DecltypeTL.setNameLoc(DS.getTypeSpecTypeLoc());
|
||||
SS.Extend(Context, SourceLocation(), TLB.getTypeLocInContext(Context, T),
|
||||
ColonColonLoc);
|
||||
return false;
|
||||
}
|
||||
|
||||
/// IsInvalidUnlessNestedName - This method is used for error recovery
|
||||
/// purposes to determine whether the specified identifier is only valid as
|
||||
/// a nested name specifier, for example a namespace name. It is
|
||||
|
|
|
@ -2,8 +2,7 @@
|
|||
|
||||
struct S {
|
||||
S *p = this; // ok
|
||||
decltype(this) q; // expected-error {{invalid use of 'this' outside of a nonstatic member function}} \
|
||||
expected-error {{C++ requires a type specifier for all declarations}}
|
||||
decltype(this) q; // expected-error {{invalid use of 'this' outside of a nonstatic member function}}
|
||||
|
||||
int arr[sizeof(this)]; // expected-error {{invalid use of 'this' outside of a nonstatic member function}}
|
||||
int sz = sizeof(this); // ok
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
|
||||
|
||||
struct global {
|
||||
};
|
||||
|
||||
namespace PR10127 {
|
||||
struct outer {
|
||||
struct middle {
|
||||
struct inner {
|
||||
int func();
|
||||
int i;
|
||||
};
|
||||
struct inner2 {
|
||||
};
|
||||
struct inner3 {
|
||||
};
|
||||
int mfunc();
|
||||
};
|
||||
typedef int td_int;
|
||||
};
|
||||
|
||||
struct str {
|
||||
operator decltype(outer::middle::inner()) ();
|
||||
operator decltype(outer::middle())::inner2 ();
|
||||
operator decltype(outer())::middle::inner3 ();
|
||||
str(int (decltype(outer::middle::inner())::*n)(),
|
||||
int (decltype(outer::middle())::inner::*o)(),
|
||||
int (decltype(outer())::middle::inner::*p)());
|
||||
};
|
||||
|
||||
int decltype(outer::middle())::inner::func() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
decltype(outer::middle::inner()) a;
|
||||
void scope() {
|
||||
a.decltype(outer::middle())::mfunc(); // expected-error{{'PR10127::outer::middle::mfunc' is not a member of class 'decltype(outer::middle::inner())'}}
|
||||
a.decltype(outer::middle::inner())::func();
|
||||
a.decltype(outer::middle())::inner::func();
|
||||
a.decltype(outer())::middle::inner::func();
|
||||
|
||||
a.decltype(outer())::middle::inner::~inner();
|
||||
|
||||
decltype(outer())::middle::inner().func();
|
||||
}
|
||||
decltype(outer::middle())::inner b;
|
||||
decltype(outer())::middle::inner c;
|
||||
decltype(outer())::fail d; // expected-error{{no type named 'fail' in 'PR10127::outer'}}
|
||||
decltype(outer())::fail::inner e; // expected-error{{no member named 'fail' in 'PR10127::outer'}}
|
||||
decltype()::fail f; // expected-error{{expected expression}}
|
||||
decltype()::middle::fail g; // expected-error{{expected expression}}
|
||||
|
||||
decltype(int()) h;
|
||||
decltype(int())::PR10127::outer i; // expected-error{{'decltype(int())' (aka 'int') is not a class, namespace, or scoped enumeration}}
|
||||
decltype(int())::global j; // expected-error{{'decltype(int())' (aka 'int') is not a class, namespace, or scoped enumeration}}
|
||||
|
||||
outer::middle k = decltype(outer())::middle();
|
||||
outer::middle::inner l = decltype(outer())::middle::inner();
|
||||
|
||||
template<typename T>
|
||||
struct templ {
|
||||
typename decltype(T())::middle::inner x; // expected-error{{type 'decltype(int())' (aka 'int') cannot be used prior to '::' because it has no members}}
|
||||
};
|
||||
|
||||
template class templ<int>; // expected-note{{in instantiation of template class 'PR10127::templ<int>' requested here}}
|
||||
template class templ<outer>;
|
||||
|
||||
enum class foo {
|
||||
bar,
|
||||
baz
|
||||
};
|
||||
|
||||
foo m = decltype(foo::bar)::baz;
|
||||
|
||||
enum E {
|
||||
};
|
||||
struct bar {
|
||||
enum E : decltype(outer())::td_int(4);
|
||||
enum F : decltype(outer())::td_int;
|
||||
enum G : decltype; // expected-error{{expected '(' after 'decltype'}}
|
||||
};
|
||||
}
|
Loading…
Reference in New Issue