diff options
31 files changed, 401 insertions, 93 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index d4878a99a6..7a5e5b6b26 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -1100,7 +1100,7 @@ public: UnaryTransformType::UTTKind UKind) const; /// \brief C++11 deduced auto type. - QualType getAutoType(QualType DeducedType) const; + QualType getAutoType(QualType DeducedType, bool IsDecltypeAuto) const; /// \brief C++11 deduction pattern for 'auto' type. QualType getAutoDeductType() const; diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 08f4c893a7..d045af82bb 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -1326,10 +1326,20 @@ protected: unsigned AttrKind : 32 - NumTypeBits; }; + class AutoTypeBitfields { + friend class AutoType; + + unsigned : NumTypeBits; + + /// Was this placeholder type spelled as 'decltype(auto)'? + unsigned IsDecltypeAuto : 1; + }; + union { TypeBitfields TypeBits; ArrayTypeBitfields ArrayTypeBits; AttributedTypeBitfields AttributedTypeBits; + AutoTypeBitfields AutoTypeBits; BuiltinTypeBitfields BuiltinTypeBits; FunctionTypeBitfields FunctionTypeBits; ObjCObjectTypeBitfields ObjCObjectTypeBits; @@ -3542,24 +3552,27 @@ public: } }; -/// \brief Represents a C++0x auto type. +/// \brief Represents a C++11 auto or C++1y decltype(auto) type. /// /// These types are usually a placeholder for a deduced type. However, within /// templates and before the initializer is attached, there is no deduced type /// and an auto type is type-dependent and canonical. class AutoType : public Type, public llvm::FoldingSetNode { - AutoType(QualType DeducedType) + AutoType(QualType DeducedType, bool IsDecltypeAuto) : Type(Auto, DeducedType.isNull() ? QualType(this, 0) : DeducedType, /*Dependent=*/DeducedType.isNull(), /*InstantiationDependent=*/DeducedType.isNull(), /*VariablyModified=*/false, /*ContainsParameterPack=*/false) { assert((DeducedType.isNull() || !DeducedType->isDependentType()) && "deduced a dependent type for auto"); + AutoTypeBits.IsDecltypeAuto = IsDecltypeAuto; } friend class ASTContext; // ASTContext creates these public: + bool isDecltypeAuto() const { return AutoTypeBits.IsDecltypeAuto; } + bool isSugared() const { return isDeduced(); } QualType desugar() const { return getCanonicalTypeInternal(); } @@ -3571,12 +3584,13 @@ public: } void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getDeducedType()); + Profile(ID, getDeducedType(), isDecltypeAuto()); } static void Profile(llvm::FoldingSetNodeID &ID, - QualType Deduced) { + QualType Deduced, bool IsDecltypeAuto) { ID.AddPointer(Deduced.getAsOpaquePtr()); + ID.AddBoolean(IsDecltypeAuto); } static bool classof(const Type *T) { diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index e477ef53ab..08abef120a 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -277,6 +277,11 @@ def warn_auto_storage_class : Warning< def ext_auto_storage_class : ExtWarn< "'auto' storage class specifier is not permitted in C++11, and will not " "be supported in future releases">, InGroup<DiagGroup<"auto-storage-class">>; +def ext_decltype_auto_type_specifier : ExtWarn< + "'decltype(auto)' type specifier is a C++1y extension">, InGroup<CXX1y>; +def warn_cxx11_compat_decltype_auto_type_specifier : Warning< + "'decltype(auto)' type specifier is incompatible with C++ standards before " + "C++1y">, InGroup<CXXPre1yCompat>, DefaultIgnore; def ext_for_range : ExtWarn< "range-based for loop is a C++11 extension">, InGroup<CXX11>; def warn_cxx98_compat_for_range : Warning< diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 0e5baf9779..14617160c0 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -1465,6 +1465,17 @@ def warn_dangling_std_initializer_list : Warning< "%select{the full-expression|the constructor}0">, InGroup<DiagGroup<"dangling-initializer-list">>; +// C++1y decltype(auto) type +def err_decltype_auto_cannot_be_combined : Error< + "'decltype(auto)' cannot be combined with other type specifiers">; +def err_decltype_auto_function_declarator_not_declaration : Error< + "'decltype(auto)' can only be used as a return type " + "in a function declaration">; +def err_decltype_auto_compound_type : Error< + "cannot form %select{pointer to|reference to|array of}0 'decltype(auto)'">; +def err_decltype_auto_initializer_list : Error< + "cannot deduce 'decltype(auto)' from initializer list">; + // C++11 override control def override_keyword_only_allowed_on_virtual_member_functions : Error< "only virtual member functions can be marked '%0'">; diff --git a/include/clang/Basic/Specifiers.h b/include/clang/Basic/Specifiers.h index 8706179a17..b9fda06b45 100644 --- a/include/clang/Basic/Specifiers.h +++ b/include/clang/Basic/Specifiers.h @@ -38,8 +38,8 @@ namespace clang { TST_void, TST_char, TST_wchar, // C++ wchar_t - TST_char16, // C++0x char16_t - TST_char32, // C++0x char32_t + TST_char16, // C++11 char16_t + TST_char32, // C++11 char32_t TST_int, TST_int128, TST_half, // OpenCL half, ARM NEON __fp16 @@ -57,11 +57,12 @@ namespace clang { TST_typename, // Typedef, C++ class-name or enum name, etc. TST_typeofType, TST_typeofExpr, - TST_decltype, // C++0x decltype - TST_underlyingType, // __underlying_type for C++0x - TST_auto, // C++0x auto - TST_unknown_anytype, // __unknown_anytype extension - TST_atomic, // C11 _Atomic + TST_decltype, // C++11 decltype + TST_underlyingType, // __underlying_type for C++11 + TST_auto, // C++11 auto + TST_decltype_auto, // C++1y decltype(auto) + TST_unknown_anytype, // __unknown_anytype extension + TST_atomic, // C11 _Atomic TST_image1d_t, // OpenCL image1d_t TST_image1d_array_t, // OpenCL image1d_array_t TST_image1d_buffer_t, // OpenCL image1d_buffer_t @@ -145,7 +146,7 @@ namespace clang { TSK_ExplicitSpecialization, /// This template specialization was instantiated from a template /// due to an explicit instantiation declaration request - /// (C++0x [temp.explicit]). + /// (C++11 [temp.explicit]). TSK_ExplicitInstantiationDeclaration, /// This template specialization was instantiated from a template /// due to an explicit instantiation definition request diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 812a09baa6..a61b59ca84 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -458,19 +458,13 @@ private: /// \brief Read an already-translated primary expression out of an annotation /// token. static ExprResult getExprAnnotation(Token &Tok) { - if (Tok.getAnnotationValue()) - return ExprResult((Expr *)Tok.getAnnotationValue()); - - return ExprResult(true); + return ExprResult::getFromOpaquePointer(Tok.getAnnotationValue()); } /// \brief Set the primary expression corresponding to the given annotation /// token. static void setExprAnnotation(Token &Tok, ExprResult ER) { - if (ER.isInvalid()) - Tok.setAnnotationValue(0); - else - Tok.setAnnotationValue(ER.get()); + Tok.setAnnotationValue(ER.getAsOpaquePointer()); } public: diff --git a/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h index 90f513f271..1c0a8e4d11 100644 --- a/include/clang/Sema/DeclSpec.h +++ b/include/clang/Sema/DeclSpec.h @@ -285,6 +285,7 @@ public: static const TST TST_typeofType = clang::TST_typeofType; static const TST TST_typeofExpr = clang::TST_typeofExpr; static const TST TST_decltype = clang::TST_decltype; + static const TST TST_decltype_auto = clang::TST_decltype_auto; static const TST TST_underlyingType = clang::TST_underlyingType; static const TST TST_auto = clang::TST_auto; static const TST TST_unknown_anytype = clang::TST_unknown_anytype; @@ -504,6 +505,10 @@ public: SourceRange getTypeofParensRange() const { return TypeofParensRange; } void setTypeofParensRange(SourceRange range) { TypeofParensRange = range; } + bool containsPlaceholderType() const { + return TypeSpecType == TST_auto || TypeSpecType == TST_decltype_auto; + } + /// \brief Turn a type-specifier-type into a string like "_Bool" or "union". static const char *getSpecifierName(DeclSpec::TST T); static const char *getSpecifierName(DeclSpec::TQ Q); diff --git a/include/clang/Sema/Ownership.h b/include/clang/Sema/Ownership.h index e064b91f78..c3d1f4e0b7 100644 --- a/include/clang/Sema/Ownership.h +++ b/include/clang/Sema/Ownership.h @@ -207,6 +207,15 @@ namespace clang { assert((PtrWithInvalid & 0x01) == 0 && "Badly aligned pointer"); return *this; } + + // For types where we can fit a flag in with the pointer, provide + // conversions to/from pointer type. + static ActionResult getFromOpaquePointer(void *P) { + ActionResult Result; + Result.PtrWithInvalid = (uintptr_t)P; + return Result; + } + void *getAsOpaquePointer() const { return (void*)PtrWithInvalid; } }; /// An opaque type for threading parsed type information through the diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index f9622455c0..22ee0cfcb6 100644 --- a/lib/AST/ASTContext.cpp +++ b/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/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index d2e6d29705..8b5f21ddda 100644 --- a/lib/AST/ASTImporter.cpp +++ b/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/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index 0b77933f0b..5ad8021fac 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/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/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp index 9d1717a220..07bcb74d79 100644 --- a/lib/AST/TypePrinter.cpp +++ b/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/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp index bc634b57d9..5d77f81ee4 100644 --- a/lib/Parse/ParseCXXInlineMethods.cpp +++ b/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/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 697e95a73e..957e2eb164 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/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/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index d7f8e982aa..f1fbbb15fe 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/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/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 956ba36d3c..326056daf4 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/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/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 17c4adf7d7..ab8be570c1 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/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/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp index 00ca3d8465..dff3b64c5b 100644 --- a/lib/Parse/ParseTentative.cpp +++ b/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/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp index 7a69eef2bb..998e2c0c36 100644 --- a/lib/Sema/DeclSpec.cpp +++ b/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/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 53f726bc05..3d4f97fbd2 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/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/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index ba2291e09c..65ad83d5fc 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/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/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index d559833c48..a681371c9b 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/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, |