diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2018-08-02 17:33:11 +0000 | 
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2018-08-02 17:33:11 +0000 | 
| commit | c7e70c433efc6953dc3888b9fbf9f3512d7da2b0 (patch) | |
| tree | 27425930fc0c91650a7f3527fcac8e0f92907b90 /lib/Sema/SemaDecl.cpp | |
| parent | 486754660bb926339aefcf012a3f848592babb8b (diff) | |
Notes
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 55542828f783..b92d76ad4204 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,  | 
