diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2013-04-26 16:15:35 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2013-04-26 16:15:35 +0000 |
commit | 74aeef50a0cc0547f387a38d32b77a2592ccc823 (patch) | |
tree | fe9ab0af5b819e3903258ff5c2ab860573a7f66c /clang/lib | |
parent | af7e8c367f25d6e6cbc6ab50f56ad41d42617f7d (diff) | |
download | bcm5719-llvm-74aeef50a0cc0547f387a38d32b77a2592ccc823.tar.gz bcm5719-llvm-74aeef50a0cc0547f387a38d32b77a2592ccc823.zip |
Implement C++1y decltype(auto).
llvm-svn: 180610
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/AST/ASTContext.cpp | 10 | ||||
-rw-r--r-- | clang/lib/AST/ASTImporter.cpp | 4 | ||||
-rw-r--r-- | clang/lib/AST/ItaniumMangle.cpp | 2 | ||||
-rw-r--r-- | clang/lib/AST/TypePrinter.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Parse/ParseCXXInlineMethods.cpp | 3 | ||||
-rw-r--r-- | clang/lib/Parse/ParseDecl.cpp | 3 | ||||
-rw-r--r-- | clang/lib/Parse/ParseDeclCXX.cpp | 79 | ||||
-rw-r--r-- | clang/lib/Parse/ParseExpr.cpp | 8 | ||||
-rw-r--r-- | clang/lib/Parse/ParseExprCXX.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Parse/ParseTentative.cpp | 1 | ||||
-rw-r--r-- | clang/lib/Sema/DeclSpec.cpp | 43 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 5 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExprCXX.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateDeduction.cpp | 24 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateVariadic.cpp | 1 | ||||
-rw-r--r-- | clang/lib/Sema/SemaType.cpp | 69 | ||||
-rw-r--r-- | clang/lib/Sema/TreeTransform.h | 12 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTReader.cpp | 7 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTWriter.cpp | 1 |
19 files changed, 207 insertions, 71 deletions
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index f9622455c0f..22ee0cfcb69 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -3516,17 +3516,19 @@ QualType ASTContext::getUnaryTransformType(QualType BaseType, } /// getAutoType - We only unique auto types after they've been deduced. -QualType ASTContext::getAutoType(QualType DeducedType) const { +QualType ASTContext::getAutoType(QualType DeducedType, + bool IsDecltypeAuto) const { void *InsertPos = 0; if (!DeducedType.isNull()) { // Look in the folding set for an existing type. llvm::FoldingSetNodeID ID; - AutoType::Profile(ID, DeducedType); + AutoType::Profile(ID, DeducedType, IsDecltypeAuto); if (AutoType *AT = AutoTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(AT, 0); } - AutoType *AT = new (*this, TypeAlignment) AutoType(DeducedType); + AutoType *AT = new (*this, TypeAlignment) AutoType(DeducedType, + IsDecltypeAuto); Types.push_back(AT); if (InsertPos) AutoTypes.InsertNode(AT, InsertPos); @@ -3564,7 +3566,7 @@ QualType ASTContext::getAtomicType(QualType T) const { /// getAutoDeductType - Get type pattern for deducing against 'auto'. QualType ASTContext::getAutoDeductType() const { if (AutoDeductTy.isNull()) - AutoDeductTy = getAutoType(QualType()); + AutoDeductTy = getAutoType(QualType(), false); assert(!AutoDeductTy.isNull() && "can't build 'auto' pattern"); return AutoDeductTy; } diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index d2e6d297053..8b5f21ddda0 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -1680,7 +1680,7 @@ QualType ASTNodeImporter::VisitUnaryTransformType(const UnaryTransformType *T) { } QualType ASTNodeImporter::VisitAutoType(const AutoType *T) { - // FIXME: Make sure that the "to" context supports C++0x! + // FIXME: Make sure that the "to" context supports C++11! QualType FromDeduced = T->getDeducedType(); QualType ToDeduced; if (!FromDeduced.isNull()) { @@ -1689,7 +1689,7 @@ QualType ASTNodeImporter::VisitAutoType(const AutoType *T) { return QualType(); } - return Importer.getToContext().getAutoType(ToDeduced); + return Importer.getToContext().getAutoType(ToDeduced, T->isDecltypeAuto()); } QualType ASTNodeImporter::VisitRecordType(const RecordType *T) { diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 0b77933f0b4..5ad8021fac9 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -2275,7 +2275,7 @@ void CXXNameMangler::mangleType(const AutoType *T) { QualType D = T->getDeducedType(); // <builtin-type> ::= Da # dependent auto if (D.isNull()) - Out << "Da"; + Out << (T->isDecltypeAuto() ? "Dc" : "Da"); else mangleType(D); } diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index 9d1717a220c..07bcb74d79b 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -779,7 +779,7 @@ void TypePrinter::printAutoBefore(const AutoType *T, raw_ostream &OS) { if (T->isDeduced()) { printBefore(T->getDeducedType(), OS); } else { - OS << "auto"; + OS << (T->isDecltypeAuto() ? "decltype(auto)" : "auto"); spaceBeforePlaceHolder(OS); } } diff --git a/clang/lib/Parse/ParseCXXInlineMethods.cpp b/clang/lib/Parse/ParseCXXInlineMethods.cpp index bc634b57d9c..5d77f81ee4b 100644 --- a/clang/lib/Parse/ParseCXXInlineMethods.cpp +++ b/clang/lib/Parse/ParseCXXInlineMethods.cpp @@ -57,8 +57,7 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, if (FnD) { Actions.ProcessDeclAttributeList(getCurScope(), FnD, AccessAttrs, false, true); - bool TypeSpecContainsAuto - = D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto; + bool TypeSpecContainsAuto = D.getDeclSpec().containsPlaceholderType(); if (Init.isUsable()) Actions.AddInitializerToDecl(FnD, Init.get(), false, TypeSpecContainsAuto); diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 697e95a73ef..957e2eb1649 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -1809,8 +1809,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, } } - bool TypeContainsAuto = - D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto; + bool TypeContainsAuto = D.getDeclSpec().containsPlaceholderType(); // Parse declarator '=' initializer. // If a '==' or '+=' is found, suggest a fixit to '='. diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index d7f8e982aa5..f1fbbb15fed 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -674,15 +674,15 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){ T.getCloseLocation()); } -/// ParseDecltypeSpecifier - Parse a C++0x decltype specifier. +/// ParseDecltypeSpecifier - Parse a C++11 decltype specifier. /// /// 'decltype' ( expression ) +/// 'decltype' ( 'auto' ) [C++1y] /// SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) { assert((Tok.is(tok::kw_decltype) || Tok.is(tok::annot_decltype)) && "Not a decltype specifier"); - ExprResult Result; SourceLocation StartLoc = Tok.getLocation(); SourceLocation EndLoc; @@ -709,29 +709,44 @@ SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) { 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, - 0, /*IsDecltype=*/true); - Result = ParseExpression(); - if (Result.isInvalid()) { - DS.SetTypeSpecError(); - if (SkipUntil(tok::r_paren, /*StopAtSemi=*/true, /*DontConsume=*/true)) { - EndLoc = ConsumeParen(); - } else { - if (PP.isBacktrackEnabled() && Tok.is(tok::semi)) { - // Backtrack to get the location of the last token before the semi. - PP.RevertCachedTokens(2); - ConsumeToken(); // the semi. - EndLoc = ConsumeAnyToken(); - assert(Tok.is(tok::semi)); + // Check for C++1y 'decltype(auto)'. + if (Tok.is(tok::kw_auto)) { + // No need to disambiguate here: an expression can't start with 'auto', + // because the typename-specifier in a function-style cast operation can't + // be 'auto'. + Diag(Tok.getLocation(), + getLangOpts().CPlusPlus1y + ? diag::warn_cxx11_compat_decltype_auto_type_specifier + : diag::ext_decltype_auto_type_specifier); + ConsumeToken(); + } else { + // Parse the expression + + // C++11 [dcl.type.simple]p4: + // The operand of the decltype specifier is an unevaluated operand. + EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated, + 0, /*IsDecltype=*/true); + Result = ParseExpression(); + if (Result.isInvalid()) { + DS.SetTypeSpecError(); + if (SkipUntil(tok::r_paren, /*StopAtSemi=*/true, + /*DontConsume=*/true)) { + EndLoc = ConsumeParen(); } else { - EndLoc = Tok.getLocation(); + if (PP.isBacktrackEnabled() && Tok.is(tok::semi)) { + // Backtrack to get the location of the last token before the semi. + PP.RevertCachedTokens(2); + ConsumeToken(); // the semi. + EndLoc = ConsumeAnyToken(); + assert(Tok.is(tok::semi)); + } else { + EndLoc = Tok.getLocation(); + } } + return EndLoc; } - return EndLoc; + + Result = Actions.ActOnDecltypeExpression(Result.take()); } // Match the ')' @@ -743,7 +758,6 @@ SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) { return T.getCloseLocation(); } - Result = Actions.ActOnDecltypeExpression(Result.take()); if (Result.isInvalid()) { DS.SetTypeSpecError(); return T.getCloseLocation(); @@ -751,12 +765,16 @@ SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) { EndLoc = T.getCloseLocation(); } + assert(!Result.isInvalid()); 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())) { + if (Result.get() + ? DS.SetTypeSpecType(DeclSpec::TST_decltype, StartLoc, PrevSpec, + DiagID, Result.release()) + : DS.SetTypeSpecType(DeclSpec::TST_decltype_auto, StartLoc, PrevSpec, + DiagID)) { Diag(StartLoc, DiagID) << PrevSpec; DS.SetTypeSpecError(); } @@ -773,8 +791,10 @@ void Parser::AnnotateExistingDecltypeSpecifier(const DeclSpec& DS, PP.EnterToken(Tok); Tok.setKind(tok::annot_decltype); - setExprAnnotation(Tok, DS.getTypeSpecType() == TST_decltype ? - DS.getRepAsExpr() : ExprResult()); + setExprAnnotation(Tok, + DS.getTypeSpecType() == TST_decltype ? DS.getRepAsExpr() : + DS.getTypeSpecType() == TST_decltype_auto ? ExprResult() : + ExprError()); Tok.setAnnotationEndLoc(EndLoc); Tok.setLocation(StartLoc); PP.AnnotateCachedTokens(Tok); @@ -2267,11 +2287,10 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, SkipUntil(tok::comma, true, true); else if (ThisDecl) Actions.AddInitializerToDecl(ThisDecl, Init.get(), EqualLoc.isInvalid(), - DS.getTypeSpecType() == DeclSpec::TST_auto); + DS.containsPlaceholderType()); } else if (ThisDecl && DS.getStorageClassSpec() == DeclSpec::SCS_static) { // No initializer. - Actions.ActOnUninitializedDecl(ThisDecl, - DS.getTypeSpecType() == DeclSpec::TST_auto); + Actions.ActOnUninitializedDecl(ThisDecl, DS.containsPlaceholderType()); } if (ThisDecl) { diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index 956ba36d3c8..326056daf44 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -691,8 +691,14 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, Res = getExprAnnotation(Tok); ConsumeToken(); break; - + case tok::kw_decltype: + // Annotate the token and tail recurse. + if (TryAnnotateTypeOrScopeToken()) + return ExprError(); + assert(Tok.isNot(tok::kw_decltype)); + return ParseCastExpression(isUnaryExpression, isAddressOfOperand); + case tok::identifier: { // primary-expression: identifier // unqualified-id: identifier // constant: enumeration-constant diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index 17c4adf7d7e..ab8be570c1a 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -1455,7 +1455,7 @@ bool Parser::ParseCXXCondition(ExprResult &ExprOut, if (!InitExpr.isInvalid()) Actions.AddInitializerToDecl(DeclOut, InitExpr.take(), !CopyInitialization, - DS.getTypeSpecType() == DeclSpec::TST_auto); + DS.containsPlaceholderType()); // FIXME: Build a reference to this declaration? Convert it to bool? // (This is currently handled by Sema). diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp index 00ca3d84654..dff3b64c5b3 100644 --- a/clang/lib/Parse/ParseTentative.cpp +++ b/clang/lib/Parse/ParseTentative.cpp @@ -942,6 +942,7 @@ bool Parser::isTentativelyDeclared(IdentifierInfo *II) { /// [GNU] '_Complex' /// [C++11] 'auto' /// [C++11] 'decltype' ( expression ) +/// [C++1y] 'decltype' ( 'auto' ) /// /// type-name: /// class-name diff --git a/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp index 7a69eef2bb1..998e2c0c367 100644 --- a/clang/lib/Sema/DeclSpec.cpp +++ b/clang/lib/Sema/DeclSpec.cpp @@ -294,6 +294,11 @@ bool Declarator::isDeclarationOfFunction() const { case TST_event_t: return false; + case TST_decltype_auto: + // This must have an initializer, so can't be a function declaration, + // even if the initializer has function type. + return false; + case TST_decltype: case TST_typeofExpr: if (Expr *E = DS.getRepAsExpr()) @@ -434,6 +439,7 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T) { case DeclSpec::TST_typeofExpr: return "typeof"; case DeclSpec::TST_auto: return "auto"; case DeclSpec::TST_decltype: return "(decltype)"; + case DeclSpec::TST_decltype_auto: return "decltype(auto)"; case DeclSpec::TST_underlyingType: return "__underlying_type"; case DeclSpec::TST_unknown_anytype: return "__unknown_anytype"; case DeclSpec::TST_atomic: return "_Atomic"; @@ -494,7 +500,7 @@ bool DeclSpec::SetStorageClassSpec(Sema &S, SCS SC, SourceLocation Loc, } if (StorageClassSpec != SCS_unspecified) { - // Maybe this is an attempt to use C++0x 'auto' outside of C++0x mode. + // Maybe this is an attempt to use C++11 'auto' outside of C++11 mode. bool isInvalid = true; if (TypeSpecType == TST_unspecified && S.getLangOpts().CPlusPlus) { if (SC == SCS_auto) @@ -834,6 +840,39 @@ void DeclSpec::Finish(DiagnosticsEngine &D, Preprocessor &PP) { // Check the type specifier components first. + // If decltype(auto) is used, no other type specifiers are permitted. + if (TypeSpecType == TST_decltype_auto && + (TypeSpecWidth != TSW_unspecified || + TypeSpecComplex != TSC_unspecified || + TypeSpecSign != TSS_unspecified || + TypeAltiVecVector || TypeAltiVecPixel || TypeAltiVecBool || + TypeQualifiers)) { + const int NumLocs = 8; + SourceLocation ExtraLocs[NumLocs] = { + TSWLoc, TSCLoc, TSSLoc, AltiVecLoc, + TQ_constLoc, TQ_restrictLoc, TQ_volatileLoc, TQ_atomicLoc + }; + FixItHint Hints[NumLocs]; + SourceLocation FirstLoc; + for (unsigned I = 0; I != NumLocs; ++I) { + if (!ExtraLocs[I].isInvalid()) { + if (FirstLoc.isInvalid() || + PP.getSourceManager().isBeforeInTranslationUnit(ExtraLocs[I], + FirstLoc)) + FirstLoc = ExtraLocs[I]; + Hints[I] = FixItHint::CreateRemoval(ExtraLocs[I]); + } + } + TypeSpecWidth = TSW_unspecified; + TypeSpecComplex = TSC_unspecified; + TypeSpecSign = TSS_unspecified; + TypeAltiVecVector = TypeAltiVecPixel = TypeAltiVecBool = false; + TypeQualifiers = 0; + Diag(D, TSTLoc, diag::err_decltype_auto_cannot_be_combined) + << Hints[0] << Hints[1] << Hints[2] << Hints[3] + << Hints[4] << Hints[5] << Hints[6] << Hints[7]; + } + // Validate and finalize AltiVec vector declspec. if (TypeAltiVecVector) { if (TypeAltiVecBool) { @@ -973,7 +1012,7 @@ void DeclSpec::Finish(DiagnosticsEngine &D, Preprocessor &PP) { StorageClassSpecLoc = SourceLocation(); } // Diagnose if we've recovered from an ill-formed 'auto' storage class - // specifier in a pre-C++0x dialect of C++. + // specifier in a pre-C++11 dialect of C++. if (!PP.getLangOpts().CPlusPlus11 && TypeSpecType == TST_auto) Diag(D, TSTLoc, diag::ext_auto_type_specifier); if (PP.getLangOpts().CPlusPlus && !PP.getLangOpts().CPlusPlus11 && diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 53f726bc051..3d4f97fbd25 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -4844,8 +4844,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, // If this decl has an auto type in need of deduction, make a note of the // Decl so we can diagnose uses of it in its own initializer. - if (D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto && - R->getContainedAutoType()) + if (D.getDeclSpec().containsPlaceholderType() && R->getContainedAutoType()) ParsingInitForAutoVars.insert(NewVD); if (D.isInvalidType() || Invalid) @@ -8166,7 +8165,7 @@ Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS, getASTContext().addUnnamedTag(Tag); return BuildDeclaratorGroup(Decls.data(), Decls.size(), - DS.getTypeSpecType() == DeclSpec::TST_auto); + DS.containsPlaceholderType()); } /// BuildDeclaratorGroup - convert a list of declarations into a declaration diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index ba2291e09cf..65ad83d5fcb 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -996,7 +996,7 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, SourceLocation PlacementLParen, MultiExprArg PlacementArgs, SourceLocation PlacementRParen, SourceRange TypeIdParens, Declarator &D, Expr *Initializer) { - bool TypeContainsAuto = D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto; + bool TypeContainsAuto = D.getDeclSpec().containsPlaceholderType(); Expr *ArraySize = 0; // If the specified type is an array, unwrap it and save the expression. diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index d559833c481..a681371c9b2 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -3579,11 +3579,13 @@ namespace { // auto type deduced as T" in order for [temp.deduct.call]p3 to apply. if (isa<TemplateTypeParmType>(Replacement)) { QualType Result = Replacement; - TemplateTypeParmTypeLoc NewTL = TLB.push<TemplateTypeParmTypeLoc>(Result); + TemplateTypeParmTypeLoc NewTL = + TLB.push<TemplateTypeParmTypeLoc>(Result); NewTL.setNameLoc(TL.getNameLoc()); return Result; } else { - QualType Result = RebuildAutoType(Replacement); + QualType Result = RebuildAutoType(Replacement, + TL.getTypePtr()->isDecltypeAuto()); AutoTypeLoc NewTL = TLB.push<AutoTypeLoc>(Result); NewTL.setNameLoc(TL.getNameLoc()); return Result; @@ -3657,6 +3659,24 @@ Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init, return DAR_Succeeded; } + // If this is a 'decltype(auto)' specifier, do the decltype dance. + // Since 'decltype(auto)' can only occur at the top of the type, we + // don't need to go digging for it. + if (const AutoType *AT = Type->getType()->getAs<AutoType>()) { + if (AT->isDecltypeAuto()) { + if (isa<InitListExpr>(Init)) { + Diag(Init->getLocStart(), diag::err_decltype_auto_initializer_list); + return DAR_FailedAlreadyDiagnosed; + } + + QualType Deduced = BuildDecltypeType(Init, Init->getLocStart()); + // FIXME: Support a non-canonical deduced type for 'auto'. + Deduced = Context.getCanonicalType(Deduced); + Result = SubstituteAutoTransform(*this, Deduced).TransformType(Type); + return DAR_Succeeded; + } + } + SourceLocation Loc = Init->getExprLoc(); LocalInstantiationScope InstScope(*this); diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp index c0ad2be6d40..db885aeec7b 100644 --- a/clang/lib/Sema/SemaTemplateVariadic.cpp +++ b/clang/lib/Sema/SemaTemplateVariadic.cpp @@ -727,6 +727,7 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) { case TST_interface: case TST_class: case TST_auto: + case TST_decltype_auto: case TST_unknown_anytype: case TST_image1d_t: case TST_image1d_array_t: diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 5289d15c34a..8bf5143beda 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -994,11 +994,14 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { } break; - case DeclSpec::TST_auto: { + case DeclSpec::TST_auto: // TypeQuals handled by caller. - Result = Context.getAutoType(QualType()); + Result = Context.getAutoType(QualType(), /*decltype(auto)*/false); + break; + + case DeclSpec::TST_decltype_auto: + Result = Context.getAutoType(QualType(), /*decltype(auto)*/true); break; - } case DeclSpec::TST_unknown_anytype: Result = Context.UnknownAnyTy; @@ -1457,12 +1460,6 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, return QualType(); } - if (T->getContainedAutoType()) { - Diag(Loc, diag::err_illegal_decl_array_of_auto) - << getPrintableNameForEntity(Entity) << T; - return QualType(); - } - if (const RecordType *EltTy = T->getAs<RecordType>()) { // If the element type is a struct or union that contains a variadic // array, accept it as a GNU extension: C99 6.7.2.1p2. @@ -2063,7 +2060,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, // In C++11, a function declarator using 'auto' must have a trailing return // type (this is checked later) and we can skip this. In other languages // using auto, we need to check regardless. - if (D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto && + if (D.getDeclSpec().containsPlaceholderType() && (!SemaRef.getLangOpts().CPlusPlus11 || !D.isFunctionDeclarator())) { int Error = -1; @@ -2402,6 +2399,46 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, (T->castAs<FunctionProtoType>()->getTypeQuals() != 0 || T->castAs<FunctionProtoType>()->getRefQualifier() != RQ_None); + // If T is 'decltype(auto)', the only declarators we can have are parens + // and at most one function declarator if this is a function declaration. + if (const AutoType *AT = T->getAs<AutoType>()) { + if (AT->isDecltypeAuto()) { + for (unsigned I = 0, E = D.getNumTypeObjects(); I != E; ++I) { + unsigned Index = E - I - 1; + DeclaratorChunk &DeclChunk = D.getTypeObject(Index); + unsigned DiagId = diag::err_decltype_auto_compound_type; + unsigned DiagKind = 0; + switch (DeclChunk.Kind) { + case DeclaratorChunk::Paren: + continue; + case DeclaratorChunk::Function: { + unsigned FnIndex; + if (D.isFunctionDeclarationContext() && + D.isFunctionDeclarator(FnIndex) && FnIndex == Index) + continue; + DiagId = diag::err_decltype_auto_function_declarator_not_declaration; + break; + } + case DeclaratorChunk::Pointer: + case DeclaratorChunk::BlockPointer: + case DeclaratorChunk::MemberPointer: + DiagKind = 0; + break; + case DeclaratorChunk::Reference: + DiagKind = 1; + break; + case DeclaratorChunk::Array: + DiagKind = 2; + break; + } + + S.Diag(DeclChunk.Loc, DiagId) << DiagKind; + D.setInvalidType(true); + break; + } + } + } + // Walk the DeclTypeInfo, building the recursive type as we go. // DeclTypeInfos are ordered from the identifier out, which is // opposite of what we want :). @@ -2530,6 +2567,15 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, } } + if (const AutoType *AT = T->getContainedAutoType()) { + // We've already diagnosed this for decltype(auto). + if (!AT->isDecltypeAuto()) { + S.Diag(DeclType.Loc, diag::err_illegal_decl_array_of_auto) + << getPrintableNameForEntity(Name) << T; + D.setInvalidType(true); + } + } + T = S.BuildArrayType(T, ASM, ArraySize, ATI.TypeQuals, SourceRange(DeclType.Loc, DeclType.EndLoc), Name); break; @@ -2560,7 +2606,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, << T << D.getDeclSpec().getSourceRange(); D.setInvalidType(true); } else if (D.getContext() != Declarator::LambdaExprContext && - (T.hasQualifiers() || !isa<AutoType>(T))) { + (T.hasQualifiers() || !isa<AutoType>(T) || + cast<AutoType>(T)->isDecltypeAuto())) { S.Diag(D.getDeclSpec().getTypeSpecTypeLoc(), diag::err_trailing_return_without_auto) << T << D.getDeclSpec().getSourceRange(); diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 97316f89b32..c0bc34fa975 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -754,17 +754,17 @@ public: UnaryTransformType::UTTKind UKind, SourceLocation Loc); - /// \brief Build a new C++0x decltype type. + /// \brief Build a new C++11 decltype type. /// /// By default, performs semantic analysis when building the decltype type. /// Subclasses may override this routine to provide different behavior. QualType RebuildDecltypeType(Expr *Underlying, SourceLocation Loc); - /// \brief Build a new C++0x auto type. + /// \brief Build a new C++11 auto type. /// /// By default, builds a new AutoType with the given deduced type. - QualType RebuildAutoType(QualType Deduced) { - return SemaRef.Context.getAutoType(Deduced); + QualType RebuildAutoType(QualType Deduced, bool IsDecltypeAuto) { + return SemaRef.Context.getAutoType(Deduced, IsDecltypeAuto); } /// \brief Build a new template specialization type. @@ -3407,7 +3407,7 @@ TreeTransform<Derived>::TransformQualifiedType(TypeLocBuilder &TLB, Qs.removeObjCLifetime(); Deduced = SemaRef.Context.getQualifiedType(Deduced.getUnqualifiedType(), Qs); - Result = SemaRef.Context.getAutoType(Deduced); + Result = SemaRef.Context.getAutoType(Deduced, AutoTy->isDecltypeAuto()); TLB.TypeWasModifiedSafely(Result); } else { // Otherwise, complain about the addition of a qualifier to an @@ -4501,7 +4501,7 @@ QualType TreeTransform<Derived>::TransformAutoType(TypeLocBuilder &TLB, QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || NewDeduced != OldDeduced) { - Result = getDerived().RebuildAutoType(NewDeduced); + Result = getDerived().RebuildAutoType(NewDeduced, T->isDecltypeAuto()); if (Result.isNull()) return QualType(); } diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 5123b79d2e9..c06153a61a9 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -4626,8 +4626,11 @@ QualType ASTReader::readTypeRecord(unsigned Index) { return Context.getUnaryTransformType(BaseType, UnderlyingType, UKind); } - case TYPE_AUTO: - return Context.getAutoType(readType(*Loc.F, Record, Idx)); + case TYPE_AUTO: { + QualType Deduced = readType(*Loc.F, Record, Idx); + bool IsDecltypeAuto = Record[Idx++]; + return Context.getAutoType(Deduced, IsDecltypeAuto); + } case TYPE_RECORD: { if (Record.size() != 2) { diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index b6d25d22d59..c5a055072d9 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -245,6 +245,7 @@ void ASTTypeWriter::VisitUnaryTransformType(const UnaryTransformType *T) { void ASTTypeWriter::VisitAutoType(const AutoType *T) { Writer.AddTypeRef(T->getDeducedType(), Record); + Record.push_back(T->isDecltypeAuto()); Code = TYPE_AUTO; } |