[cfe-commits] r145785 - in /cfe/trunk: include/clang/AST/NestedNameSpecifier.h include/clang/Basic/DiagnosticSemaKinds.td include/clang/Basic/TokenKinds.def include/clang/Parse/Parser.h include/clang/Sema/Sema.h lib/Parse/ParseDecl.cpp lib/Parse/ParseDeclCXX.cpp lib/Parse/ParseExpr.cpp lib/Parse/ParseExprCXX.cpp lib/Parse/ParseTentative.cpp lib/Parse/Parser.cpp lib/Sema/SemaCXXScopeSpec.cpp test/CXX/expr/expr.prim/expr.prim.general/p4-0x.cpp test/CXX/expr/expr.prim/expr.prim.general/p8-0x.cpp
David Blaikie
dblaikie at gmail.com
Sat Dec 3 21:04:19 PST 2011
Author: dblaikie
Date: Sat Dec 3 23:04:18 2011
New Revision: 145785
URL: http://llvm.org/viewvc/llvm-project?rev=145785&view=rev
Log:
Support decltype in nested-name-specifiers.
Added:
cfe/trunk/test/CXX/expr/expr.prim/expr.prim.general/p8-0x.cpp
Modified:
cfe/trunk/include/clang/AST/NestedNameSpecifier.h
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/include/clang/Basic/TokenKinds.def
cfe/trunk/include/clang/Parse/Parser.h
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/Parse/ParseDecl.cpp
cfe/trunk/lib/Parse/ParseDeclCXX.cpp
cfe/trunk/lib/Parse/ParseExpr.cpp
cfe/trunk/lib/Parse/ParseExprCXX.cpp
cfe/trunk/lib/Parse/ParseTentative.cpp
cfe/trunk/lib/Parse/Parser.cpp
cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp
cfe/trunk/test/CXX/expr/expr.prim/expr.prim.general/p4-0x.cpp
Modified: cfe/trunk/include/clang/AST/NestedNameSpecifier.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/NestedNameSpecifier.h?rev=145785&r1=145784&r2=145785&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/NestedNameSpecifier.h (original)
+++ cfe/trunk/include/clang/AST/NestedNameSpecifier.h Sat Dec 3 23:04:18 2011
@@ -36,8 +36,9 @@
/// 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
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=145785&r1=145784&r2=145785&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Sat Dec 3 23:04:18 2011
@@ -3993,6 +3993,8 @@
"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<
Modified: cfe/trunk/include/clang/Basic/TokenKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/TokenKinds.def?rev=145785&r1=145784&r2=145785&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/TokenKinds.def (original)
+++ cfe/trunk/include/clang/Basic/TokenKinds.def Sat Dec 3 23:04:18 2011
@@ -560,6 +560,8 @@
// 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
Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=145785&r1=145784&r2=145785&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Sat Dec 3 23:04:18 2011
@@ -1901,7 +1901,10 @@
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);
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=145785&r1=145784&r2=145785&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Sat Dec 3 23:04:18 2011
@@ -3326,6 +3326,10 @@
bool EnteringContext,
CXXScopeSpec &SS);
+ bool ActOnCXXNestedNameSpecifierDecltype(CXXScopeSpec &SS,
+ const DeclSpec &DS,
+ SourceLocation ColonColonLoc);
+
bool IsInvalidUnlessNestedName(Scope *S, CXXScopeSpec &SS,
IdentifierInfo &Identifier,
SourceLocation IdentifierLoc,
Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=145785&r1=145784&r2=145785&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Sat Dec 3 23:04:18 2011
@@ -1889,6 +1889,7 @@
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 @@
ParseTypeofSpecifier(DS);
continue;
- case tok::kw_decltype:
+ case tok::annot_decltype:
ParseDecltypeSpecifier(DS);
continue;
@@ -2370,6 +2371,7 @@
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 @@
return true;
// C++0x decltype support.
- case tok::kw_decltype:
+ case tok::annot_decltype:
ParseDecltypeSpecifier(DS);
return true;
@@ -3346,6 +3348,7 @@
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 @@
return true;
// C++0x decltype.
- case tok::kw_decltype:
+ case tok::annot_decltype:
return true;
// C1x _Atomic()
@@ -3968,6 +3971,10 @@
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 @@
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 @@
// 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 @@
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 @@
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 @@
EndLoc = Range.getEnd();
}
}
-
- // Leave prototype scope.
- PrototypeScope.Exit();
}
// Remember that we parsed a function type, and remember the attributes.
Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=145785&r1=145784&r2=145785&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Sat Dec 3 23:04:18 2011
@@ -632,39 +632,85 @@
///
/// '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;
- // Parse the expression
+ if (Tok.is(tok::annot_decltype)) {
+ Result = getExprAnnotation(Tok);
+ EndLoc = Tok.getAnnotationEndLoc();
+ ConsumeToken();
+ if (Result.isInvalid()) {
+ DS.SetTypeSpecError();
+ return EndLoc;
+ }
+ } else {
+ ConsumeToken();
- // 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;
- }
+ 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();
+ }
- // Match the ')'
- T.consumeClose();
- if (T.getCloseLocation().isInvalid())
- return;
+ // 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();
+ }
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 @@
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);
Modified: cfe/trunk/lib/Parse/ParseExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExpr.cpp?rev=145785&r1=145784&r2=145785&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseExpr.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExpr.cpp Sat Dec 3 23:04:18 2011
@@ -664,6 +664,7 @@
ConsumeToken();
break;
+ case tok::kw_decltype:
case tok::identifier: { // primary-expression: identifier
// unqualified-id: identifier
// constant: enumeration-constant
Modified: cfe/trunk/lib/Parse/ParseExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=145785&r1=145784&r2=145785&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Sat Dec 3 23:04:18 2011
@@ -168,6 +168,22 @@
*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:
Modified: cfe/trunk/lib/Parse/ParseTentative.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseTentative.cpp?rev=145785&r1=145784&r2=145785&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseTentative.cpp (original)
+++ cfe/trunk/lib/Parse/ParseTentative.cpp Sat Dec 3 23:04:18 2011
@@ -706,7 +706,6 @@
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 @@
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 @@
}
// C++0x decltype support.
- case tok::kw_decltype:
+ case tok::annot_decltype:
return TPResult::True();
// C++0x type traits support
Modified: cfe/trunk/lib/Parse/Parser.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/Parser.cpp?rev=145785&r1=145784&r2=145785&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/Parser.cpp (original)
+++ cfe/trunk/lib/Parse/Parser.cpp Sat Dec 3 23:04:18 2011
@@ -1202,8 +1202,8 @@
/// 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 @@
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))
Modified: cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp?rev=145785&r1=145784&r2=145785&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp Sat Dec 3 23:04:18 2011
@@ -676,6 +676,29 @@
/*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
Modified: cfe/trunk/test/CXX/expr/expr.prim/expr.prim.general/p4-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.prim/expr.prim.general/p4-0x.cpp?rev=145785&r1=145784&r2=145785&view=diff
==============================================================================
--- cfe/trunk/test/CXX/expr/expr.prim/expr.prim.general/p4-0x.cpp (original)
+++ cfe/trunk/test/CXX/expr/expr.prim/expr.prim.general/p4-0x.cpp Sat Dec 3 23:04:18 2011
@@ -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
Added: cfe/trunk/test/CXX/expr/expr.prim/expr.prim.general/p8-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.prim/expr.prim.general/p8-0x.cpp?rev=145785&view=auto
==============================================================================
--- cfe/trunk/test/CXX/expr/expr.prim/expr.prim.general/p8-0x.cpp (added)
+++ cfe/trunk/test/CXX/expr/expr.prim/expr.prim.general/p8-0x.cpp Sat Dec 3 23:04:18 2011
@@ -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'}}
+ };
+}
More information about the cfe-commits
mailing list