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/Sema | |
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/Sema')
-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 |
7 files changed, 131 insertions, 25 deletions
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(); } |