diff options
Diffstat (limited to 'lib/Sema/SemaDecl.cpp')
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 136 |
1 files changed, 117 insertions, 19 deletions
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 55542828f7839..b92d76ad42049 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -3182,7 +3182,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, if (OldTypeInfo.getNoCallerSavedRegs() != NewTypeInfo.getNoCallerSavedRegs()) { if (NewTypeInfo.getNoCallerSavedRegs()) { - AnyX86NoCallerSavedRegistersAttr *Attr = + AnyX86NoCallerSavedRegistersAttr *Attr = New->getAttr<AnyX86NoCallerSavedRegistersAttr>(); Diag(New->getLocation(), diag::err_function_attribute_mismatch) << Attr; Diag(OldLocation, diag::note_previous_declaration); @@ -6008,6 +6008,31 @@ static void checkAttributesAfterMerging(Sema &S, NamedDecl &ND) { << Attr; ND.dropAttr<NotTailCalledAttr>(); } + + // Check the attributes on the function type, if any. + if (const auto *FD = dyn_cast<FunctionDecl>(&ND)) { + // Don't declare this variable in the second operand of the for-statement; + // GCC miscompiles that by ending its lifetime before evaluating the + // third operand. See gcc.gnu.org/PR86769. + AttributedTypeLoc ATL; + for (TypeLoc TL = FD->getTypeSourceInfo()->getTypeLoc(); + (ATL = TL.getAsAdjusted<AttributedTypeLoc>()); + TL = ATL.getModifiedLoc()) { + // The [[lifetimebound]] attribute can be applied to the implicit object + // parameter of a non-static member function (other than a ctor or dtor) + // by applying it to the function type. + if (ATL.getAttrKind() == AttributedType::attr_lifetimebound) { + const auto *MD = dyn_cast<CXXMethodDecl>(FD); + if (!MD || MD->isStatic()) { + S.Diag(ATL.getAttrNameLoc(), diag::err_lifetimebound_no_object_param) + << !MD << ATL.getLocalSourceRange(); + } else if (isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD)) { + S.Diag(ATL.getAttrNameLoc(), diag::err_lifetimebound_ctor_dtor) + << isa<CXXDestructorDecl>(MD) << ATL.getLocalSourceRange(); + } + } + } + } } static void checkDLLAttributeRedeclaration(Sema &S, NamedDecl *OldDecl, @@ -8049,6 +8074,29 @@ enum OpenCLParamType { RecordKernelParam }; +static bool isOpenCLSizeDependentType(ASTContext &C, QualType Ty) { + // Size dependent types are just typedefs to normal integer types + // (e.g. unsigned long), so we cannot distinguish them from other typedefs to + // integers other than by their names. + StringRef SizeTypeNames[] = {"size_t", "intptr_t", "uintptr_t", "ptrdiff_t"}; + + // Remove typedefs one by one until we reach a typedef + // for a size dependent type. + QualType DesugaredTy = Ty; + do { + ArrayRef<StringRef> Names(SizeTypeNames); + auto Match = + std::find(Names.begin(), Names.end(), DesugaredTy.getAsString()); + if (Names.end() != Match) + return true; + + Ty = DesugaredTy; + DesugaredTy = Ty.getSingleStepDesugaredType(C); + } while (DesugaredTy != Ty); + + return false; +} + static OpenCLParamType getOpenCLKernelParameterType(Sema &S, QualType PT) { if (PT->isPointerType()) { QualType PointeeType = PT->getPointeeType(); @@ -8061,8 +8109,13 @@ static OpenCLParamType getOpenCLKernelParameterType(Sema &S, QualType PT) { return PtrKernelParam; } - // TODO: Forbid the other integer types (size_t, ptrdiff_t...) when they can - // be used as builtin types. + // OpenCL v1.2 s6.9.k: + // Arguments to kernel functions in a program cannot be declared with the + // built-in scalar types bool, half, size_t, ptrdiff_t, intptr_t, and + // uintptr_t or a struct and/or union that contain fields declared to be one + // of these built-in scalar types. + if (isOpenCLSizeDependentType(S.getASTContext(), PT)) + return InvalidKernelParam; if (PT->isImageType()) return PtrKernelParam; @@ -8079,6 +8132,15 @@ static OpenCLParamType getOpenCLKernelParameterType(Sema &S, QualType PT) { if (PT->isRecordType()) return RecordKernelParam; + // Look into an array argument to check if it has a forbidden type. + if (PT->isArrayType()) { + const Type *UnderlyingTy = PT->getPointeeOrArrayElementType(); + // Call ourself to check an underlying type of an array. Since the + // getPointeeOrArrayElementType returns an innermost type which is not an + // array, this recusive call only happens once. + return getOpenCLKernelParameterType(S, QualType(UnderlyingTy, 0)); + } + return ValidKernelParam; } @@ -8124,8 +8186,20 @@ static void checkIsValidOpenCLKernelParameter( // of event_t type. // Do not diagnose half type since it is diagnosed as invalid argument // type for any function elsewhere. - if (!PT->isHalfType()) + if (!PT->isHalfType()) { S.Diag(Param->getLocation(), diag::err_bad_kernel_param_type) << PT; + + // Explain what typedefs are involved. + const TypedefType *Typedef = nullptr; + while ((Typedef = PT->getAs<TypedefType>())) { + SourceLocation Loc = Typedef->getDecl()->getLocation(); + // SourceLocation may be invalid for a built-in type. + if (Loc.isValid()) + S.Diag(Loc, diag::note_entity_declared_at) << PT; + PT = Typedef->desugar(); + } + } + D.setInvalidType(); return; @@ -8146,9 +8220,14 @@ static void checkIsValidOpenCLKernelParameter( SmallVector<const FieldDecl *, 4> HistoryStack; HistoryStack.push_back(nullptr); - const RecordDecl *PD = PT->castAs<RecordType>()->getDecl(); - VisitStack.push_back(PD); + // At this point we already handled everything except of a RecordType or + // an ArrayType of a RecordType. + assert((PT->isArrayType() || PT->isRecordType()) && "Unexpected type."); + const RecordType *RecTy = + PT->getPointeeOrArrayElementType()->getAs<RecordType>(); + const RecordDecl *OrigRecDecl = RecTy->getDecl(); + VisitStack.push_back(RecTy->getDecl()); assert(VisitStack.back() && "First decl null?"); do { @@ -8167,7 +8246,15 @@ static void checkIsValidOpenCLKernelParameter( const RecordDecl *RD; if (const FieldDecl *Field = dyn_cast<FieldDecl>(Next)) { HistoryStack.push_back(Field); - RD = Field->getType()->castAs<RecordType>()->getDecl(); + + QualType FieldTy = Field->getType(); + // Other field types (known to be valid or invalid) are handled while we + // walk around RecordDecl::fields(). + assert((FieldTy->isArrayType() || FieldTy->isRecordType()) && + "Unexpected type."); + const Type *FieldRecTy = FieldTy->getPointeeOrArrayElementType(); + + RD = FieldRecTy->castAs<RecordType>()->getDecl(); } else { RD = cast<RecordDecl>(Next); } @@ -8204,8 +8291,8 @@ static void checkIsValidOpenCLKernelParameter( S.Diag(Param->getLocation(), diag::err_bad_kernel_param_type) << PT; } - S.Diag(PD->getLocation(), diag::note_within_field_of_type) - << PD->getDeclName(); + S.Diag(OrigRecDecl->getLocation(), diag::note_within_field_of_type) + << OrigRecDecl->getDeclName(); // We have an error, now let's go back up through history and show where // the offending field came from @@ -10720,7 +10807,7 @@ QualType Sema::deduceVarTypeFromInitializer(VarDecl *VDecl, InitializedEntity Entity = InitializedEntity::InitializeVariable(VDecl); InitializationKind Kind = InitializationKind::CreateForInit( VDecl->getLocation(), DirectInit, Init); - // FIXME: Initialization should not be taking a mutable list of inits. + // FIXME: Initialization should not be taking a mutable list of inits. SmallVector<Expr*, 8> InitsCopy(DeduceInits.begin(), DeduceInits.end()); return DeduceTemplateSpecializationFromInitializer(TSI, Entity, Kind, InitsCopy); @@ -11914,14 +12001,25 @@ void Sema::FinalizeDeclaration(Decl *ThisDecl) { NewAttr->setInherited(true); VD->addAttr(NewAttr); } - // CUDA E.2.9.4: Within the body of a __device__ or __global__ - // function, only __shared__ variables may be declared with - // static storage class. - if (getLangOpts().CUDA && !VD->hasAttr<CUDASharedAttr>() && - CUDADiagIfDeviceCode(VD->getLocation(), - diag::err_device_static_local_var) - << CurrentCUDATarget()) - VD->setInvalidDecl(); + // CUDA 8.0 E.3.9.4: Within the body of a __device__ or __global__ + // function, only __shared__ variables or variables without any device + // memory qualifiers may be declared with static storage class. + // Note: It is unclear how a function-scope non-const static variable + // without device memory qualifier is implemented, therefore only static + // const variable without device memory qualifier is allowed. + [&]() { + if (!getLangOpts().CUDA) + return; + if (VD->hasAttr<CUDASharedAttr>()) + return; + if (VD->getType().isConstQualified() && + !(VD->hasAttr<CUDADeviceAttr>() || VD->hasAttr<CUDAConstantAttr>())) + return; + if (CUDADiagIfDeviceCode(VD->getLocation(), + diag::err_device_static_local_var) + << CurrentCUDATarget()) + VD->setInvalidDecl(); + }(); } } @@ -13398,7 +13496,7 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) { break; } } - + if (Context.BuiltinInfo.isReturnsTwice(BuiltinID) && !FD->hasAttr<ReturnsTwiceAttr>()) FD->addAttr(ReturnsTwiceAttr::CreateImplicit(Context, |