comex created this revision. comex added a subscriber: cfe-commits. Herald added subscribers: aemerson, klimek.
Add support for GCC's '__auto_type' extension. As per the GCC manual: https://gcc.gnu.org/onlinedocs/gcc/Typeof.html Implemented in GCC 4.9, __auto_type is similar to C++11 auto but works in C. The most compelling use case is for macros; the above manual page explains the need pretty well, so I won't repeat it here. This implementation differs from GCC's in also supporting __auto_type in C++, treating it the same as auto. I don't see any good reason not to, because otherwise headers intended to be used from both languages can't use it (you could use a define that expands to '__auto_type' or 'auto' depending on the language, but then C++ pre-11 is broken). However, for sanity's sake, it prevents using __auto_type instead of auto with C++11+-specific functionality such as 'decltype(auto)', auto arguments to lambdas, and auto before a trailing return type. **It also differs by allowing all of the following (by default, due to reusing the C++ auto behavior) which GCC rejects: initializing with the value of a bit field, using '__auto_type *', and declaring multiple variables in one statement. (The first of those extends a preexisting difference: GCC does not allow typeof on a bit field, while Clang currently does. Arguably a bug, as the C standard prohibits using sizeof on them.) Maybe this should be tightened for the sake of compatibility, although it doesn't otherwise seem harmful to allow them (the latter two, anyway). Opinions desired. Making this work in clang is pretty straightforward: most of the patch is only needed to fix up diagnostics. (This is my first patch submission, so please let me know if I've done things wrong.) http://reviews.llvm.org/D12686 Files: include/clang/AST/ASTContext.h include/clang/AST/Type.h include/clang/Basic/DiagnosticGroups.td include/clang/Basic/DiagnosticParseKinds.td include/clang/Basic/DiagnosticSemaKinds.td include/clang/Basic/Specifiers.h include/clang/Basic/TokenKinds.def include/clang/Sema/DeclSpec.h lib/AST/ASTContext.cpp lib/AST/ASTImporter.cpp lib/AST/Type.cpp lib/AST/TypePrinter.cpp lib/Format/TokenAnnotator.cpp lib/Parse/ParseDecl.cpp lib/Parse/ParseDeclCXX.cpp lib/Parse/ParseObjc.cpp lib/Parse/ParseTentative.cpp lib/Sema/DeclSpec.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaTemplateDeduction.cpp lib/Sema/SemaTemplateVariadic.cpp lib/Sema/SemaType.cpp lib/Sema/TreeTransform.h lib/Serialization/ASTReader.cpp lib/Serialization/ASTWriter.cpp test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-1y.cpp test/Sema/auto-type.c test/SemaCXX/auto-type-from-cxx.cpp
Index: test/SemaCXX/auto-type-from-cxx.cpp =================================================================== --- /dev/null +++ test/SemaCXX/auto-type-from-cxx.cpp @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -std=c++14 -fsyntax-only -verify %s + +__auto_type a() -> int; // expected-error {{function with trailing return type must specify return type 'auto', not '__auto_type'}} +int b() { + decltype(__auto_type) c = 1; // expected-error {{expected expression}} + auto _ = [](__auto_type d) {}; // expected-error {{'__auto_type' not allowed in lambda parameter}} + __auto_type e = 2; +} + Index: test/Sema/auto-type.c =================================================================== --- /dev/null +++ test/Sema/auto-type.c @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 %s -fsyntax-only -verify -pedantic -std=c11 + +__auto_type a = 5; // expected-warning {{'__auto_type' is a GNU extension}} +__extension__ __auto_type a1 = 5; +#pragma clang diagnostic ignored "-Wgnu-auto-type" +__auto_type b = 5.0; +__auto_type c = &b; +__auto_type d = (struct {int a;}) {5}; +_Static_assert(__builtin_types_compatible_p(__typeof(a), int), ""); +__auto_type e = e; // expected-error {{variable 'e' declared with '__auto_type' type cannot appear in its own initializer}} + +struct s { __auto_type a; }; // expected-error {{'__auto_type' not allowed in struct member}} + +__auto_type f = 1, g = 1.0; // expected-error {{'__auto_type' deduced as 'int' in declaration of 'f' and deduced as 'double' in declaration of 'g'}} + +__auto_type a() {} // expected-error {{'__auto_type' not allowed in function return type}} Index: test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-1y.cpp =================================================================== --- test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-1y.cpp +++ test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-1y.cpp @@ -3,9 +3,9 @@ // FIXME: This is in p11 (?) in C++1y. void f() { - decltype(auto) a = a; // expected-error{{variable 'a' declared with 'auto' type cannot appear in its own initializer}} - if (decltype(auto) b = b) {} // expected-error {{variable 'b' declared with 'auto' type cannot appear in its own initializer}} - decltype(auto) c = ({ decltype(auto) d = c; 0; }); // expected-error {{variable 'c' declared with 'auto' type cannot appear in its own initializer}} + decltype(auto) a = a; // expected-error{{variable 'a' declared with 'decltype(auto)' type cannot appear in its own initializer}} + if (decltype(auto) b = b) {} // expected-error {{variable 'b' declared with 'decltype(auto)' type cannot appear in its own initializer}} + decltype(auto) c = ({ decltype(auto) d = c; 0; }); // expected-error {{variable 'c' declared with 'decltype(auto)' type cannot appear in its own initializer}} } void g() { Index: lib/Serialization/ASTWriter.cpp =================================================================== --- lib/Serialization/ASTWriter.cpp +++ lib/Serialization/ASTWriter.cpp @@ -280,7 +280,7 @@ void ASTTypeWriter::VisitAutoType(const AutoType *T) { Writer.AddTypeRef(T->getDeducedType(), Record); - Record.push_back(T->isDecltypeAuto()); + Record.push_back((unsigned)T->getKeyword()); if (T->getDeducedType().isNull()) Record.push_back(T->isDependentType()); Code = TYPE_AUTO; Index: lib/Serialization/ASTReader.cpp =================================================================== --- lib/Serialization/ASTReader.cpp +++ lib/Serialization/ASTReader.cpp @@ -5250,9 +5250,9 @@ case TYPE_AUTO: { QualType Deduced = readType(*Loc.F, Record, Idx); - bool IsDecltypeAuto = Record[Idx++]; + AutoTypeKeyword Keyword = (AutoTypeKeyword)Record[Idx++]; bool IsDependent = Deduced.isNull() ? Record[Idx++] : false; - return Context.getAutoType(Deduced, IsDecltypeAuto, IsDependent); + return Context.getAutoType(Deduced, Keyword, IsDependent); } case TYPE_RECORD: { Index: lib/Sema/TreeTransform.h =================================================================== --- lib/Sema/TreeTransform.h +++ lib/Sema/TreeTransform.h @@ -844,11 +844,11 @@ /// \brief Build a new C++11 auto type. /// /// By default, builds a new AutoType with the given deduced type. - QualType RebuildAutoType(QualType Deduced, bool IsDecltypeAuto) { + QualType RebuildAutoType(QualType Deduced, AutoTypeKeyword Keyword) { // Note, IsDependent is always false here: we implicitly convert an 'auto' // which has been deduced to a dependent type into an undeduced 'auto', so // that we'll retry deduction after the transformation. - return SemaRef.Context.getAutoType(Deduced, IsDecltypeAuto, + return SemaRef.Context.getAutoType(Deduced, Keyword, /*IsDependent*/ false); } @@ -3863,7 +3863,7 @@ Qs.removeObjCLifetime(); Deduced = SemaRef.Context.getQualifiedType(Deduced.getUnqualifiedType(), Qs); - Result = SemaRef.Context.getAutoType(Deduced, AutoTy->isDecltypeAuto(), + Result = SemaRef.Context.getAutoType(Deduced, AutoTy->getKeyword(), AutoTy->isDependentType()); TLB.TypeWasModifiedSafely(Result); } else { @@ -5066,7 +5066,7 @@ QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || NewDeduced != OldDeduced || T->isDependentType()) { - Result = getDerived().RebuildAutoType(NewDeduced, T->isDecltypeAuto()); + Result = getDerived().RebuildAutoType(NewDeduced, T->getKeyword()); if (Result.isNull()) return QualType(); } Index: lib/Sema/SemaType.cpp =================================================================== --- lib/Sema/SemaType.cpp +++ lib/Sema/SemaType.cpp @@ -1448,6 +1448,7 @@ break; case DeclSpec::TST_auto: + case DeclSpec::TST_auto_type: // TypeQuals handled by caller. // If auto is mentioned in a lambda parameter context, convert it to a // template parameter type immediately, with the appropriate depth and @@ -1480,14 +1481,17 @@ // template type parameter. Result = QualType(CorrespondingTemplateParam->getTypeForDecl(), 0); } else { - Result = Context.getAutoType(QualType(), /*decltype(auto)*/false, false); + Result = Context.getAutoType(QualType(), + DS.getTypeSpecType() == DeclSpec::TST_auto_type ? + AutoTypeKeyword::AutoTypeExt : AutoTypeKeyword::Auto, + false); } break; case DeclSpec::TST_decltype_auto: - Result = Context.getAutoType(QualType(), - /*decltype(auto)*/true, - /*IsDependent*/ false); + Result = Context.getAutoType(QualType(), + /*Keyword*/ AutoTypeKeyword::DecltypeAuto, + /*IsDependent*/ false); break; case DeclSpec::TST_unknown_anytype: @@ -2608,46 +2612,48 @@ case Declarator::LambdaExprParameterContext: if (!(SemaRef.getLangOpts().CPlusPlus14 && D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto)) - Error = 14; + Error = 16; break; - case Declarator::MemberContext: + case Declarator::MemberContext: { if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static) break; + bool Cxx = SemaRef.getLangOpts().CPlusPlus; switch (cast<TagDecl>(SemaRef.CurContext)->getTagKind()) { case TTK_Enum: llvm_unreachable("unhandled tag kind"); - case TTK_Struct: Error = 1; /* Struct member */ break; - case TTK_Union: Error = 2; /* Union member */ break; - case TTK_Class: Error = 3; /* Class member */ break; - case TTK_Interface: Error = 4; /* Interface member */ break; + case TTK_Struct: Error = Cxx ? 1 : 2; /* Struct member */ break; + case TTK_Union: Error = Cxx ? 3 : 4; /* Union member */ break; + case TTK_Class: Error = 5; /* Class member */ break; + case TTK_Interface: Error = 6; /* Interface member */ break; } break; + } case Declarator::CXXCatchContext: case Declarator::ObjCCatchContext: - Error = 5; // Exception declaration + Error = 7; // Exception declaration break; case Declarator::TemplateParamContext: - Error = 6; // Template parameter + Error = 8; // Template parameter break; case Declarator::BlockLiteralContext: - Error = 7; // Block literal + Error = 9; // Block literal break; case Declarator::TemplateTypeArgContext: - Error = 8; // Template type argument + Error = 10; // Template type argument break; case Declarator::AliasDeclContext: case Declarator::AliasTemplateContext: - Error = 10; // Type alias + Error = 12; // Type alias break; case Declarator::TrailingReturnContext: if (!SemaRef.getLangOpts().CPlusPlus14) - Error = 11; // Function return type + Error = 13; // Function return type break; case Declarator::ConversionIdContext: if (!SemaRef.getLangOpts().CPlusPlus14) - Error = 12; // conversion-type-id + Error = 14; // conversion-type-id break; case Declarator::TypeNameContext: - Error = 13; // Generic + Error = 15; // Generic break; case Declarator::FileContext: case Declarator::BlockContext: @@ -2658,11 +2664,11 @@ } if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) - Error = 9; + Error = 11; // In Objective-C it is an error to use 'auto' on a function declarator. if (D.isFunctionDeclarator()) - Error = 11; + Error = 13; // C++11 [dcl.spec.auto]p2: 'auto' is always fine if the declarator // contains a trailing return type. That is only legal at the outermost @@ -2688,10 +2694,10 @@ AutoRange = D.getName().getSourceRange(); if (Error != -1) { - const bool IsDeclTypeAuto = - D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_decltype_auto; + const unsigned Keyword = + D.getDeclSpec().getTypeSpecType() - DeclSpec::TST_auto; SemaRef.Diag(AutoRange.getBegin(), diag::err_auto_not_allowed) - << IsDeclTypeAuto << Error << AutoRange; + << Keyword << Error << AutoRange; T = SemaRef.Context.IntTy; D.setInvalidType(true); } else @@ -3697,7 +3703,7 @@ D.setInvalidType(true); } else if (D.getContext() != Declarator::LambdaExprContext && (T.hasQualifiers() || !isa<AutoType>(T) || - cast<AutoType>(T)->isDecltypeAuto())) { + cast<AutoType>(T)->getKeyword() != AutoTypeKeyword::Auto)) { S.Diag(D.getDeclSpec().getTypeSpecTypeLoc(), diag::err_trailing_return_without_auto) << T << D.getDeclSpec().getSourceRange(); Index: lib/Sema/SemaTemplateVariadic.cpp =================================================================== --- lib/Sema/SemaTemplateVariadic.cpp +++ lib/Sema/SemaTemplateVariadic.cpp @@ -737,6 +737,7 @@ case TST_interface: case TST_class: case TST_auto: + case TST_auto_type: case TST_decltype_auto: case TST_unknown_anytype: case TST_error: Index: lib/Sema/SemaTemplateDeduction.cpp =================================================================== --- lib/Sema/SemaTemplateDeduction.cpp +++ lib/Sema/SemaTemplateDeduction.cpp @@ -3908,7 +3908,7 @@ !Replacement.isNull() && Replacement->isDependentType(); QualType Result = SemaRef.Context.getAutoType(Dependent ? QualType() : Replacement, - TL.getTypePtr()->isDecltypeAuto(), + TL.getTypePtr()->getKeyword(), Dependent); AutoTypeLoc NewTL = TLB.push<AutoTypeLoc>(Result); NewTL.setNameLoc(TL.getNameLoc()); Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -349,8 +349,10 @@ // See if this is an auto-typed variable whose initializer we are parsing. if (ParsingInitForAutoVars.count(D)) { + const AutoType* AT = cast<VarDecl>(D)->getType().getTypePtr()->getContainedAutoType(); + Diag(Loc, diag::err_auto_variable_cannot_appear_in_own_initializer) - << D->getDeclName(); + << D->getDeclName() << (unsigned)AT->getKeyword(); return true; } Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -111,6 +111,7 @@ case tok::kw_wchar_t: case tok::kw_bool: case tok::kw___underlying_type: + case tok::kw___auto_type: return true; case tok::annot_typename: @@ -5723,7 +5724,10 @@ NewVD = VarDecl::Create(Context, DC, D.getLocStart(), D.getIdentifierLoc(), II, R, TInfo, SC); - + + if (D.getDeclSpec().containsPlaceholderType() && R->getContainedAutoType()) + ParsingInitForAutoVars.insert(NewVD); + if (D.isInvalidType()) NewVD->setInvalidDecl(); } else { @@ -10096,7 +10100,7 @@ } else if (DeducedCanon != UCanon) { Diag(D->getTypeSourceInfo()->getTypeLoc().getBeginLoc(), diag::err_auto_different_deductions) - << (AT->isDecltypeAuto() ? 1 : 0) + << (unsigned)AT->getKeyword() << Deduced << DeducedDecl->getDeclName() << U << D->getDeclName() << DeducedDecl->getInit()->getSourceRange() Index: lib/Sema/DeclSpec.cpp =================================================================== --- lib/Sema/DeclSpec.cpp +++ lib/Sema/DeclSpec.cpp @@ -288,6 +288,7 @@ switch (DS.getTypeSpecType()) { case TST_atomic: case TST_auto: + case TST_auto_type: case TST_bool: case TST_char: case TST_char16: @@ -471,6 +472,7 @@ case DeclSpec::TST_typeofType: case DeclSpec::TST_typeofExpr: return "typeof"; case DeclSpec::TST_auto: return "auto"; + case DeclSpec::TST_auto_type: return "__auto_type"; case DeclSpec::TST_decltype: return "(decltype)"; case DeclSpec::TST_decltype_auto: return "decltype(auto)"; case DeclSpec::TST_underlyingType: return "__underlying_type"; Index: lib/Parse/ParseTentative.cpp =================================================================== --- lib/Parse/ParseTentative.cpp +++ lib/Parse/ParseTentative.cpp @@ -1224,6 +1224,7 @@ case tok::kw_extern: case tok::kw_mutable: case tok::kw_auto: + case tok::kw___auto_type: case tok::kw___thread: case tok::kw_thread_local: case tok::kw__Thread_local: @@ -1515,6 +1516,7 @@ case tok::kw_double: case tok::kw_void: case tok::kw___unknown_anytype: + case tok::kw___auto_type: return true; case tok::kw_auto: Index: lib/Parse/ParseObjc.cpp =================================================================== --- lib/Parse/ParseObjc.cpp +++ lib/Parse/ParseObjc.cpp @@ -1114,6 +1114,7 @@ case tok::kw__Bool: case tok::kw__Complex: case tok::kw___alignof: + case tok::kw___auto_type: IdentifierInfo *II = Tok.getIdentifierInfo(); SelectorLoc = ConsumeToken(); return II; Index: lib/Parse/ParseDeclCXX.cpp =================================================================== --- lib/Parse/ParseDeclCXX.cpp +++ lib/Parse/ParseDeclCXX.cpp @@ -1116,6 +1116,7 @@ case tok::kw_typedef: // struct foo {...} typedef x; case tok::kw_register: // struct foo {...} register x; case tok::kw_auto: // struct foo {...} auto x; + case tok::kw___auto_type: // struct foo {...} __auto_type x; case tok::kw_mutable: // struct foo {...} mutable x; case tok::kw_thread_local: // struct foo {...} thread_local x; case tok::kw_constexpr: // struct foo {...} constexpr x; Index: lib/Parse/ParseDecl.cpp =================================================================== --- lib/Parse/ParseDecl.cpp +++ lib/Parse/ParseDecl.cpp @@ -3145,6 +3145,11 @@ PrevSpec, DiagID, Policy); isStorageClass = true; break; + case tok::kw___auto_type: + Diag(Tok, diag::ext_auto_type); + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_auto_type, Loc, PrevSpec, + DiagID, Policy); + break; case tok::kw_register: isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_register, Loc, PrevSpec, DiagID, Policy); @@ -4446,6 +4451,7 @@ case tok::kw___private_extern__: case tok::kw_static: case tok::kw_auto: + case tok::kw___auto_type: case tok::kw_register: case tok::kw___thread: case tok::kw_thread_local: Index: lib/Format/TokenAnnotator.cpp =================================================================== --- lib/Format/TokenAnnotator.cpp +++ lib/Format/TokenAnnotator.cpp @@ -906,7 +906,7 @@ (!Line.MightBeFunctionDecl || Current.NestingLevel != 0)) { Contexts.back().FirstStartOfName = &Current; Current.Type = TT_StartOfName; - } else if (Current.is(tok::kw_auto)) { + } else if (Current.isOneOf(tok::kw_auto, tok::kw___auto_type)) { AutoFound = true; } else if (Current.is(tok::arrow) && Style.Language == FormatStyle::LK_Java) { Index: lib/AST/TypePrinter.cpp =================================================================== --- lib/AST/TypePrinter.cpp +++ lib/AST/TypePrinter.cpp @@ -835,7 +835,11 @@ if (!T->getDeducedType().isNull()) { printBefore(T->getDeducedType(), OS); } else { - OS << (T->isDecltypeAuto() ? "decltype(auto)" : "auto"); + switch (T->getKeyword()) { + case AutoTypeKeyword::Auto: OS << "auto"; break; + case AutoTypeKeyword::DecltypeAuto: OS << "decltype(auto)"; break; + case AutoTypeKeyword::AutoTypeExt: OS << "__auto_type"; break; + } spaceBeforePlaceHolder(OS); } } Index: lib/AST/Type.cpp =================================================================== --- lib/AST/Type.cpp +++ lib/AST/Type.cpp @@ -947,7 +947,7 @@ == T->getDeducedType().getAsOpaquePtr()) return QualType(T, 0); - return Ctx.getAutoType(deducedType, T->isDecltypeAuto(), + return Ctx.getAutoType(deducedType, T->getKeyword(), T->isDependentType()); } Index: lib/AST/ASTImporter.cpp =================================================================== --- lib/AST/ASTImporter.cpp +++ lib/AST/ASTImporter.cpp @@ -1746,7 +1746,7 @@ return QualType(); } - return Importer.getToContext().getAutoType(ToDeduced, T->isDecltypeAuto(), + return Importer.getToContext().getAutoType(ToDeduced, T->getKeyword(), /*IsDependent*/false); } Index: lib/AST/ASTContext.cpp =================================================================== --- lib/AST/ASTContext.cpp +++ lib/AST/ASTContext.cpp @@ -3931,20 +3931,20 @@ /// getAutoType - Return the uniqued reference to the 'auto' type which has been /// deduced to the given type, or to the canonical undeduced 'auto' type, or the /// canonical deduced-but-dependent 'auto' type. -QualType ASTContext::getAutoType(QualType DeducedType, bool IsDecltypeAuto, +QualType ASTContext::getAutoType(QualType DeducedType, AutoTypeKeyword Keyword, bool IsDependent) const { - if (DeducedType.isNull() && !IsDecltypeAuto && !IsDependent) + if (DeducedType.isNull() && Keyword == AutoTypeKeyword::Auto && !IsDependent) return getAutoDeductType(); // Look in the folding set for an existing type. void *InsertPos = nullptr; llvm::FoldingSetNodeID ID; - AutoType::Profile(ID, DeducedType, IsDecltypeAuto, IsDependent); + AutoType::Profile(ID, DeducedType, Keyword, IsDependent); if (AutoType *AT = AutoTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(AT, 0); AutoType *AT = new (*this, TypeAlignment) AutoType(DeducedType, - IsDecltypeAuto, + Keyword, IsDependent); Types.push_back(AT); if (InsertPos) @@ -3984,7 +3984,7 @@ QualType ASTContext::getAutoDeductType() const { if (AutoDeductTy.isNull()) AutoDeductTy = QualType( - new (*this, TypeAlignment) AutoType(QualType(), /*decltype(auto)*/false, + new (*this, TypeAlignment) AutoType(QualType(), AutoTypeKeyword::Auto, /*dependent*/false), 0); return AutoDeductTy; Index: include/clang/Sema/DeclSpec.h =================================================================== --- include/clang/Sema/DeclSpec.h +++ include/clang/Sema/DeclSpec.h @@ -301,6 +301,7 @@ 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_auto_type = clang::TST_auto_type; static const TST TST_unknown_anytype = clang::TST_unknown_anytype; static const TST TST_atomic = clang::TST_atomic; static const TST TST_error = clang::TST_error; @@ -512,7 +513,8 @@ void setTypeofParensRange(SourceRange range) { TypeofParensRange = range; } bool containsPlaceholderType() const { - return TypeSpecType == TST_auto || TypeSpecType == TST_decltype_auto; + return (TypeSpecType == TST_auto || TypeSpecType == TST_auto_type || + TypeSpecType == TST_decltype_auto); } bool hasTagDefinition() const; Index: include/clang/Basic/TokenKinds.def =================================================================== --- include/clang/Basic/TokenKinds.def +++ include/clang/Basic/TokenKinds.def @@ -377,6 +377,7 @@ KEYWORD(__thread , KEYALL) KEYWORD(__FUNCTION__ , KEYALL) KEYWORD(__PRETTY_FUNCTION__ , KEYALL) +KEYWORD(__auto_type , KEYALL) // GNU Extensions (outside impl-reserved namespace) KEYWORD(typeof , KEYGNU) Index: include/clang/Basic/Specifiers.h =================================================================== --- include/clang/Basic/Specifiers.h +++ include/clang/Basic/Specifiers.h @@ -64,6 +64,7 @@ TST_underlyingType, // __underlying_type for C++11 TST_auto, // C++11 auto TST_decltype_auto, // C++1y decltype(auto) + TST_auto_type, // __auto_type extension TST_unknown_anytype, // __unknown_anytype extension TST_atomic, // C11 _Atomic TST_error // erroneous type Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -1657,15 +1657,18 @@ "'auto' type specifier is incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore; def err_auto_variable_cannot_appear_in_own_initializer : Error< - "variable %0 declared with 'auto' type cannot appear in its own initializer">; + "variable %0 declared with %select{'auto'|'decltype(auto)'|'__auto_type'}1 " + "type cannot appear in its own initializer">; def err_illegal_decl_array_of_auto : Error< "'%0' declared as array of %1">; def err_new_array_of_auto : Error< "cannot allocate array of 'auto'">; def err_auto_not_allowed : Error< - "%select{'auto'|'decltype(auto)'}0 not allowed %select{in function prototype" - "|in non-static struct member" - "|in non-static union member|in non-static class member|in interface member" + "%select{'auto'|'decltype(auto)'|'__auto_type'}0 not allowed " + "%select{in function prototype" + "|in non-static struct member|in struct member" + "|in non-static union member|in union member" + "|in non-static class member|in interface member" "|in exception declaration|in template parameter|in block literal" "|in template argument|in typedef|in type alias|in function return type" "|in conversion function type|here|in lambda parameter}1">; @@ -1706,8 +1709,8 @@ def err_auto_new_deduction_failure : Error< "new expression for type %0 has incompatible constructor argument of type %1">; def err_auto_different_deductions : Error< - "'%select{auto|decltype(auto)}0' deduced as %1 in declaration of %2 and " - "deduced as %3 in declaration of %4">; + "'%select{auto|decltype(auto)|__auto_type}0' deduced as %1 in declaration " + "of %2 and deduced as %3 in declaration of %4">; def err_implied_std_initializer_list_not_found : Error< "cannot deduce type of initializer list because std::initializer_list was " "not found; include <initializer_list>">; Index: include/clang/Basic/DiagnosticParseKinds.td =================================================================== --- include/clang/Basic/DiagnosticParseKinds.td +++ include/clang/Basic/DiagnosticParseKinds.td @@ -299,6 +299,9 @@ def warn_cxx11_compat_decltype_auto_type_specifier : Warning< "'decltype(auto)' type specifier is incompatible with C++ standards before " "C++14">, InGroup<CXXPre14Compat>, DefaultIgnore; +def ext_auto_type : Extension< + "'__auto_type' is a GNU extension">, + InGroup<GNUAutoType>; def ext_for_range : ExtWarn< "range-based for loop is a C++11 extension">, InGroup<CXX11>; def warn_cxx98_compat_for_range : Warning< Index: include/clang/Basic/DiagnosticGroups.td =================================================================== --- include/clang/Basic/DiagnosticGroups.td +++ include/clang/Basic/DiagnosticGroups.td @@ -24,6 +24,7 @@ def GNUAlignofExpression : DiagGroup<"gnu-alignof-expression">; def AmbigMemberTemplate : DiagGroup<"ambiguous-member-template">; def GNUAnonymousStruct : DiagGroup<"gnu-anonymous-struct">; +def GNUAutoType : DiagGroup<"gnu-auto-type">; def ArrayBounds : DiagGroup<"array-bounds">; def ArrayBoundsPointerArithmetic : DiagGroup<"array-bounds-pointer-arithmetic">; def Availability : DiagGroup<"availability">; @@ -699,6 +700,7 @@ // A warning group for warnings about GCC extensions. def GNU : DiagGroup<"gnu", [GNUAlignofExpression, GNUAnonymousStruct, + GNUAutoType, GNUBinaryLiteral, GNUCaseRange, GNUComplexInteger, GNUCompoundLiteralInitializer, GNUConditionalOmittedOperand, GNUDesignator, Index: include/clang/AST/Type.h =================================================================== --- include/clang/AST/Type.h +++ include/clang/AST/Type.h @@ -1206,6 +1206,16 @@ RQ_RValue }; +/// Which keyword(s) were used to create an AutoType. +enum struct AutoTypeKeyword : unsigned char { + /// \brief auto + Auto, + /// \brief decltype(auto) + DecltypeAuto, + /// \brief __auto_type (GNU extension) + AutoTypeExt +}; + /// The base class of the type hierarchy. /// /// A central concept with types is that each type always has a canonical @@ -1424,8 +1434,8 @@ unsigned : NumTypeBits; - /// Was this placeholder type spelled as 'decltype(auto)'? - unsigned IsDecltypeAuto : 1; + /// Was this placeholder type spelled as 'auto', 'decltype(auto)', or '__auto_type'? + AutoTypeKeyword Keyword : 2; }; union { @@ -3871,22 +3881,24 @@ /// is no deduced type and an auto type is canonical. In the latter case, it is /// also a dependent type. class AutoType : public Type, public llvm::FoldingSetNode { - AutoType(QualType DeducedType, bool IsDecltypeAuto, - bool IsDependent) + AutoType(QualType DeducedType, AutoTypeKeyword Keyword, bool IsDependent) : Type(Auto, DeducedType.isNull() ? QualType(this, 0) : DeducedType, /*Dependent=*/IsDependent, /*InstantiationDependent=*/IsDependent, /*VariablyModified=*/false, /*ContainsParameterPack=*/DeducedType.isNull() ? false : DeducedType->containsUnexpandedParameterPack()) { assert((DeducedType.isNull() || !IsDependent) && "auto deduced to dependent type"); - AutoTypeBits.IsDecltypeAuto = IsDecltypeAuto; + AutoTypeBits.Keyword = Keyword; } friend class ASTContext; // ASTContext creates these public: - bool isDecltypeAuto() const { return AutoTypeBits.IsDecltypeAuto; } + bool isDecltypeAuto() const { + return AutoTypeBits.Keyword == AutoTypeKeyword::DecltypeAuto; + } + AutoTypeKeyword getKeyword() const { return AutoTypeBits.Keyword; } bool isSugared() const { return !isCanonicalUnqualified(); } QualType desugar() const { return getCanonicalTypeInternal(); } @@ -3901,14 +3913,13 @@ } void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getDeducedType(), isDecltypeAuto(), - isDependentType()); + Profile(ID, getDeducedType(), AutoTypeBits.Keyword, isDependentType()); } static void Profile(llvm::FoldingSetNodeID &ID, QualType Deduced, - bool IsDecltypeAuto, bool IsDependent) { + AutoTypeKeyword Keyword, bool IsDependent) { ID.AddPointer(Deduced.getAsOpaquePtr()); - ID.AddBoolean(IsDecltypeAuto); + ID.AddInteger((unsigned)Keyword); ID.AddBoolean(IsDependent); } Index: include/clang/AST/ASTContext.h =================================================================== --- include/clang/AST/ASTContext.h +++ include/clang/AST/ASTContext.h @@ -1232,7 +1232,7 @@ UnaryTransformType::UTTKind UKind) const; /// \brief C++11 deduced auto type. - QualType getAutoType(QualType DeducedType, bool IsDecltypeAuto, + QualType getAutoType(QualType DeducedType, AutoTypeKeyword Keyword, bool IsDependent) const; /// \brief C++11 deduction pattern for 'auto' type.
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits