diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2013-04-30 13:56:41 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2013-04-30 13:56:41 +0000 |
commit | dc7a4f5d7a7e3b60d4dc4a80338d7a2728540998 (patch) | |
tree | 0fdbc7f2427ae39e5c561332fb0d7c04e4dcb65b /lib/Sema | |
parent | 24cb36d9c212f82b3d9aedd34be27ae4911bfdba (diff) |
Don't treat a non-deduced 'auto' type as being type-dependent. Instead, there
are now two distinct canonical 'AutoType's: one is the undeduced 'auto'
placeholder type, and the other is a deduced-but-dependent type. All
deduced-to-a-non-dependent-type cases are still non-canonical.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@180789 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema')
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 122 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 7 | ||||
-rw-r--r-- | lib/Sema/SemaLookup.cpp | 4 | ||||
-rw-r--r-- | lib/Sema/SemaStmt.cpp | 13 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateDeduction.cpp | 52 | ||||
-rw-r--r-- | lib/Sema/SemaType.cpp | 8 | ||||
-rw-r--r-- | lib/Sema/TreeTransform.h | 6 |
7 files changed, 107 insertions, 105 deletions
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 9a3499dc39..1e5e5bb259 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -2798,8 +2798,7 @@ void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old, bool OldWasHidden) { QualType MergedT; if (getLangOpts().CPlusPlus) { - AutoType *AT = New->getType()->getContainedAutoType(); - if (AT && !AT->isDeduced()) { + if (New->getType()->isUndeducedType()) { // We don't know what the new type is until the initializer is attached. return; } else if (Context.hasSameType(New->getType(), Old->getType())) { @@ -5142,27 +5141,18 @@ static bool mayConflictWithNonVisibleExternC(const T *ND) { return ND->isExternC(); } -/// \brief Perform semantic checking on a newly-created variable -/// declaration. -/// -/// This routine performs all of the type-checking required for a -/// variable declaration once it has been built. It is used both to -/// check variables after they have been parsed and their declarators -/// have been translated into a declaration, and to check variables -/// that have been instantiated from a template. -/// -/// Sets NewVD->isInvalidDecl() if an error was encountered. -/// -/// Returns true if the variable declaration is a redeclaration. -bool Sema::CheckVariableDeclaration(VarDecl *NewVD, - LookupResult &Previous) { +void Sema::CheckVariableDeclarationType(VarDecl *NewVD) { // If the decl is already known invalid, don't check it. if (NewVD->isInvalidDecl()) - return false; + return; TypeSourceInfo *TInfo = NewVD->getTypeSourceInfo(); QualType T = TInfo->getType(); + // Defer checking an 'auto' type until its initializer is attached. + if (T->isUndeducedType()) + return; + if (T->isObjCObjectType()) { Diag(NewVD->getLocation(), diag::err_statically_allocated_object) << FixItHint::CreateInsertion(NewVD->getLocation(), "*"); @@ -5177,7 +5167,7 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD, if (NewVD->hasLocalStorage() && T.getAddressSpace() != 0) { Diag(NewVD->getLocation(), diag::err_as_qualified_auto_decl); NewVD->setInvalidDecl(); - return false; + return; } // OpenCL v1.2 s6.5 - All program scope variables must be declared in the @@ -5187,7 +5177,7 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD, && !T->isSamplerT()){ Diag(NewVD->getLocation(), diag::err_opencl_global_invalid_addr_space); NewVD->setInvalidDecl(); - return false; + return; } // OpenCL v1.2 s6.8 -- The static qualifier is valid only in program @@ -5196,7 +5186,7 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD, && NewVD->isStaticLocal()) { Diag(NewVD->getLocation(), diag::err_static_function_scope); NewVD->setInvalidDecl(); - return false; + return; } if (NewVD->hasLocalStorage() && T.isObjCGCWeak() @@ -5237,7 +5227,7 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD, Diag(NewVD->getLocation(), diag::err_vla_decl_has_extern_linkage) << SizeRange; NewVD->setInvalidDecl(); - return false; + return; } if (FixedTInfo == 0) { @@ -5246,7 +5236,7 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD, else Diag(NewVD->getLocation(), diag::err_vm_decl_has_extern_linkage); NewVD->setInvalidDecl(); - return false; + return; } Diag(NewVD->getLocation(), diag::warn_illegal_constant_array_size); @@ -5254,6 +5244,54 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD, NewVD->setTypeSourceInfo(FixedTInfo); } + if (T->isVoidType() && NewVD->isThisDeclarationADefinition()) { + Diag(NewVD->getLocation(), diag::err_typecheck_decl_incomplete_type) + << T; + NewVD->setInvalidDecl(); + return; + } + + if (!NewVD->hasLocalStorage() && NewVD->hasAttr<BlocksAttr>()) { + Diag(NewVD->getLocation(), diag::err_block_on_nonlocal); + NewVD->setInvalidDecl(); + return; + } + + if (isVM && NewVD->hasAttr<BlocksAttr>()) { + Diag(NewVD->getLocation(), diag::err_block_on_vm); + NewVD->setInvalidDecl(); + return; + } + + if (NewVD->isConstexpr() && !T->isDependentType() && + RequireLiteralType(NewVD->getLocation(), T, + diag::err_constexpr_var_non_literal)) { + // Can't perform this check until the type is deduced. + NewVD->setInvalidDecl(); + return; + } +} + +/// \brief Perform semantic checking on a newly-created variable +/// declaration. +/// +/// This routine performs all of the type-checking required for a +/// variable declaration once it has been built. It is used both to +/// check variables after they have been parsed and their declarators +/// have been translated into a declaration, and to check variables +/// that have been instantiated from a template. +/// +/// Sets NewVD->isInvalidDecl() if an error was encountered. +/// +/// Returns true if the variable declaration is a redeclaration. +bool Sema::CheckVariableDeclaration(VarDecl *NewVD, + LookupResult &Previous) { + CheckVariableDeclarationType(NewVD); + + // If the decl is already known invalid, don't check it. + if (NewVD->isInvalidDecl()) + return false; + // If we did not find anything by this name, look for a non-visible // extern "C" declaration with the same name. // @@ -5292,32 +5330,6 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD, // Filter out any non-conflicting previous declarations. filterNonConflictingPreviousDecls(Context, NewVD, Previous); - if (T->isVoidType() && NewVD->isThisDeclarationADefinition()) { - Diag(NewVD->getLocation(), diag::err_typecheck_decl_incomplete_type) - << T; - NewVD->setInvalidDecl(); - return false; - } - - if (!NewVD->hasLocalStorage() && NewVD->hasAttr<BlocksAttr>()) { - Diag(NewVD->getLocation(), diag::err_block_on_nonlocal); - NewVD->setInvalidDecl(); - return false; - } - - if (isVM && NewVD->hasAttr<BlocksAttr>()) { - Diag(NewVD->getLocation(), diag::err_block_on_vm); - NewVD->setInvalidDecl(); - return false; - } - - if (NewVD->isConstexpr() && !T->isDependentType() && - RequireLiteralType(NewVD->getLocation(), T, - diag::err_constexpr_var_non_literal)) { - NewVD->setInvalidDecl(); - return false; - } - if (!Previous.empty()) { MergeVarDecl(NewVD, Previous, PreviousWasHidden); return true; @@ -7284,10 +7296,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, ParenListExpr *CXXDirectInit = dyn_cast<ParenListExpr>(Init); // C++11 [decl.spec.auto]p6. Deduce the type which 'auto' stands in for. - AutoType *Auto = 0; - if (TypeMayContainAuto && - (Auto = VDecl->getType()->getContainedAutoType()) && - !Auto->isDeduced()) { + if (TypeMayContainAuto && VDecl->getType()->isUndeducedType()) { Expr *DeduceInit = Init; // Initializer could be a C++ direct-initializer. Deduction only works if it // contains exactly one expression. @@ -7357,6 +7366,11 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, // the previously declared type. if (VarDecl *Old = VDecl->getPreviousDecl()) MergeVarDeclTypes(VDecl, Old, /*OldWasHidden*/ false); + + // Check the deduced type is valid for a variable declaration. + CheckVariableDeclarationType(VDecl); + if (VDecl->isInvalidDecl()) + return; } if (VDecl->isLocalVarDecl() && VDecl->hasExternalStorage()) { @@ -8190,8 +8204,8 @@ Sema::BuildDeclaratorGroup(Decl **Group, unsigned NumDecls, // Don't reissue diagnostics when instantiating a template. if (AT && D->isInvalidDecl()) break; - if (AT && AT->isDeduced()) { - QualType U = AT->getDeducedType(); + QualType U = AT ? AT->getDeducedType() : QualType(); + if (!U.isNull()) { CanQualType UCanon = Context.getCanonicalType(U); if (Deduced.isNull()) { Deduced = U; diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index c05d29d7d4..df09b4bcae 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -1118,9 +1118,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, HaveCompleteInit = true; // C++11 [decl.spec.auto]p6. Deduce the type which 'auto' stands in for. - AutoType *AT = 0; - if (TypeMayContainAuto && - (AT = AllocType->getContainedAutoType()) && !AT->isDeduced()) { + if (TypeMayContainAuto && AllocType->isUndeducedType()) { if (initStyle == CXXNewExpr::NoInit || NumInits == 0) return ExprError(Diag(StartLoc, diag::err_auto_new_requires_ctor_arg) << AllocType << TypeRange); @@ -2279,6 +2277,9 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, ExprResult Sema::CheckConditionVariable(VarDecl *ConditionVar, SourceLocation StmtLoc, bool ConvertToBoolean) { + if (ConditionVar->isInvalidDecl()) + return ExprError(); + QualType T = ConditionVar->getType(); // C++ [stmt.select]p2: diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index eab2d81f39..85a74490cb 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -2087,6 +2087,10 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) { case Type::Complex: break; + // Non-deduced auto types only get here for error cases. + case Type::Auto: + break; + // If T is an Objective-C object or interface type, or a pointer to an // object or interface type, the associated namespace is the global // namespace. diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 4fc1818d32..63c2a7d8e6 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -1923,7 +1923,15 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc, StmtResult BeginEndDecl = BeginEnd; ExprResult NotEqExpr = Cond, IncrExpr = Inc; - if (!BeginEndDecl.get() && !RangeVarType->isDependentType()) { + if (RangeVarType->isDependentType()) { + // The range is implicitly used as a placeholder when it is dependent. + RangeVar->setUsed(); + + // Deduce any 'auto's in the loop variable as 'DependentTy'. We'll fill + // them in properly when we instantiate the loop. + if (!LoopVar->isInvalidDecl() && Kind != BFRK_Check) + LoopVar->setType(SubstAutoType(LoopVar->getType(), Context.DependentTy)); + } else if (!BeginEndDecl.get()) { SourceLocation RangeLoc = RangeVar->getLocation(); const QualType RangeVarNonRefType = RangeVarType.getNonReferenceType(); @@ -2110,9 +2118,6 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc, if (LoopVar->isInvalidDecl()) NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin); } - } else { - // The range is implicitly used as a placeholder when it is dependent. - RangeVar->setUsed(); } // Don't bother to actually allocate the result if we're just trying to diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index a681371c9b..ea5b145871 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -3584,8 +3584,12 @@ namespace { NewTL.setNameLoc(TL.getNameLoc()); return Result; } else { - QualType Result = RebuildAutoType(Replacement, - TL.getTypePtr()->isDecltypeAuto()); + bool Dependent = + !Replacement.isNull() && Replacement->isDependentType(); + QualType Result = + SemaRef.Context.getAutoType(Dependent ? QualType() : Replacement, + TL.getTypePtr()->isDecltypeAuto(), + Dependent); AutoTypeLoc NewTL = TLB.push<AutoTypeLoc>(Result); NewTL.setNameLoc(TL.getNameLoc()); return Result; @@ -3597,41 +3601,6 @@ namespace { return E; } }; - - /// Determine whether the specified type (which contains an 'auto' type - /// specifier) is dependent. This is not trivial, because the 'auto' specifier - /// itself claims to be type-dependent. - bool isDependentAutoType(QualType Ty) { - while (1) { - QualType Pointee = Ty->getPointeeType(); - if (!Pointee.isNull()) { - Ty = Pointee; - } else if (const MemberPointerType *MPT = Ty->getAs<MemberPointerType>()){ - if (MPT->getClass()->isDependentType()) - return true; - Ty = MPT->getPointeeType(); - } else if (const FunctionProtoType *FPT = Ty->getAs<FunctionProtoType>()){ - for (FunctionProtoType::arg_type_iterator I = FPT->arg_type_begin(), - E = FPT->arg_type_end(); - I != E; ++I) - if ((*I)->isDependentType()) - return true; - Ty = FPT->getResultType(); - } else if (Ty->isDependentSizedArrayType()) { - return true; - } else if (const ArrayType *AT = Ty->getAsArrayTypeUnsafe()) { - Ty = AT->getElementType(); - } else if (Ty->getAs<DependentSizedExtVectorType>()) { - return true; - } else if (const VectorType *VT = Ty->getAs<VectorType>()) { - Ty = VT->getElementType(); - } else { - break; - } - } - assert(Ty->getAs<AutoType>() && "didn't find 'auto' in auto type"); - return false; - } } /// \brief Deduce the type for an auto type-specifier (C++0x [dcl.spec.auto]p6) @@ -3654,8 +3623,9 @@ Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init, Init = result.take(); } - if (Init->isTypeDependent() || isDependentAutoType(Type->getType())) { - Result = Type; + if (Init->isTypeDependent() || Type->getType()->isDependentType()) { + Result = + SubstituteAutoTransform(*this, Context.DependentTy).TransformType(Type); return DAR_Succeeded; } @@ -3749,6 +3719,10 @@ Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init, return DAR_Succeeded; } +QualType Sema::SubstAutoType(QualType Type, QualType Deduced) { + return SubstituteAutoTransform(*this, Deduced).TransformType(Type); +} + void Sema::DiagnoseAutoDeductionFailure(VarDecl *VDecl, Expr *Init) { if (isa<InitListExpr>(Init)) Diag(VDecl->getLocation(), diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 8bf5143bed..7ed16878db 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -2569,11 +2569,11 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, if (const AutoType *AT = T->getContainedAutoType()) { // We've already diagnosed this for decltype(auto). - if (!AT->isDecltypeAuto()) { + if (!AT->isDecltypeAuto()) S.Diag(DeclType.Loc, diag::err_illegal_decl_array_of_auto) << getPrintableNameForEntity(Name) << T; - D.setInvalidType(true); - } + T = QualType(); + break; } T = S.BuildArrayType(T, ASM, ArraySize, ATI.TypeQuals, @@ -3831,7 +3831,7 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state, QualType &type) { bool NonObjCPointer = false; - if (!type->isDependentType()) { + if (!type->isDependentType() && !type->isUndeducedType()) { if (const PointerType *ptr = type->getAs<PointerType>()) { QualType pointee = ptr->getPointeeType(); if (pointee->isObjCRetainableType() || pointee->isPointerType()) diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index c0bc34fa97..925860a600 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -764,6 +764,9 @@ public: /// /// By default, builds a new AutoType with the given deduced type. QualType RebuildAutoType(QualType Deduced, bool IsDecltypeAuto) { + // 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); } @@ -4500,7 +4503,8 @@ QualType TreeTransform<Derived>::TransformAutoType(TypeLocBuilder &TLB, } QualType Result = TL.getType(); - if (getDerived().AlwaysRebuild() || NewDeduced != OldDeduced) { + if (getDerived().AlwaysRebuild() || NewDeduced != OldDeduced || + T->isDependentType()) { Result = getDerived().RebuildAutoType(NewDeduced, T->isDecltypeAuto()); if (Result.isNull()) return QualType(); |