diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp | 695 |
1 files changed, 562 insertions, 133 deletions
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp index 191dbd0..5a0f0f8 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp @@ -244,11 +244,12 @@ static bool checkUInt32Argument(Sema &S, const AttributeList &Attr, /// \brief Diagnose mutually exclusive attributes when present on a given /// declaration. Returns true if diagnosed. template <typename AttrTy> -static bool checkAttrMutualExclusion(Sema &S, Decl *D, - const AttributeList &Attr) { +static bool checkAttrMutualExclusion(Sema &S, Decl *D, SourceRange Range, + IdentifierInfo *Ident) { if (AttrTy *A = D->getAttr<AttrTy>()) { - S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible) - << Attr.getName() << A; + S.Diag(Range.getBegin(), diag::err_attributes_are_not_compatible) << Ident + << A; + S.Diag(A->getLocation(), diag::note_conflicting_attribute); return true; } return false; @@ -315,7 +316,7 @@ bool Sema::checkStringLiteralArgumentAttr(const AttributeList &Attr, Diag(Loc->Loc, diag::err_attribute_argument_type) << Attr.getName() << AANT_ArgumentString << FixItHint::CreateInsertion(Loc->Loc, "\"") - << FixItHint::CreateInsertion(PP.getLocForEndOfToken(Loc->Loc), "\""); + << FixItHint::CreateInsertion(getLocForEndOfToken(Loc->Loc), "\""); Str = Loc->Ident->getName(); if (ArgLocation) *ArgLocation = Loc->Loc; @@ -432,11 +433,10 @@ static bool checkRecordTypeForCapability(Sema &S, QualType Ty) { // Else check if any base classes have a capability. if (CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(RD)) { CXXBasePaths BPaths(false, false); - if (CRD->lookupInBases([](const CXXBaseSpecifier *BS, CXXBasePath &P, - void *) { - return BS->getType()->getAs<RecordType>() - ->getDecl()->hasAttr<CapabilityAttr>(); - }, nullptr, BPaths)) + if (CRD->lookupInBases([](const CXXBaseSpecifier *BS, CXXBasePath &) { + const auto *Type = BS->getType()->getAs<RecordType>(); + return Type->getDecl()->hasAttr<CapabilityAttr>(); + }, BPaths)) return true; } return false; @@ -629,13 +629,10 @@ static bool checkAcquireOrderAttrCommon(Sema &S, Decl *D, // Check that this attribute only applies to lockable types. QualType QT = cast<ValueDecl>(D)->getType(); - if (!QT->isDependentType()) { - const RecordType *RT = getRecordType(QT); - if (!RT || !RT->getDecl()->hasAttr<CapabilityAttr>()) { - S.Diag(Attr.getLoc(), diag::warn_thread_attribute_decl_not_lockable) - << Attr.getName(); - return false; - } + if (!QT->isDependentType() && !typeHasCapability(S, QT)) { + S.Diag(Attr.getLoc(), diag::warn_thread_attribute_decl_not_lockable) + << Attr.getName(); + return false; } // Check that all arguments are lockable objects. @@ -812,6 +809,43 @@ static void handleEnableIfAttr(Sema &S, Decl *D, const AttributeList &Attr) { Attr.getAttributeSpellingListIndex())); } +static void handlePassObjectSizeAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + if (D->hasAttr<PassObjectSizeAttr>()) { + S.Diag(D->getLocStart(), diag::err_attribute_only_once_per_parameter) + << Attr.getName(); + return; + } + + Expr *E = Attr.getArgAsExpr(0); + uint32_t Type; + if (!checkUInt32Argument(S, Attr, E, Type, /*Idx=*/1)) + return; + + // pass_object_size's argument is passed in as the second argument of + // __builtin_object_size. So, it has the same constraints as that second + // argument; namely, it must be in the range [0, 3]. + if (Type > 3) { + S.Diag(E->getLocStart(), diag::err_attribute_argument_outof_range) + << Attr.getName() << 0 << 3 << E->getSourceRange(); + return; + } + + // pass_object_size is only supported on constant pointer parameters; as a + // kindness to users, we allow the parameter to be non-const for declarations. + // At this point, we have no clue if `D` belongs to a function declaration or + // definition, so we defer the constness check until later. + if (!cast<ParmVarDecl>(D)->getType()->isPointerType()) { + S.Diag(D->getLocStart(), diag::err_attribute_pointers_only) + << Attr.getName() << 1; + return; + } + + D->addAttr(::new (S.Context) + PassObjectSizeAttr(Attr.getRange(), S.Context, (int)Type, + Attr.getAttributeSpellingListIndex())); +} + static void handleConsumableAttr(Sema &S, Decl *D, const AttributeList &Attr) { ConsumableAttr::ConsumedState DefaultState; @@ -1039,17 +1073,14 @@ static void handlePackedAttr(Sema &S, Decl *D, const AttributeList &Attr) { TD->addAttr(::new (S.Context) PackedAttr(Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); else if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) { - // If the alignment is less than or equal to 8 bits, the packed attribute - // has no effect. + // Report warning about changed offset in the newer compiler versions. if (!FD->getType()->isDependentType() && - !FD->getType()->isIncompleteType() && + !FD->getType()->isIncompleteType() && FD->isBitField() && S.Context.getTypeAlign(FD->getType()) <= 8) - S.Diag(Attr.getLoc(), diag::warn_attribute_ignored_for_field_of_type) - << Attr.getName() << FD->getType(); - else - FD->addAttr(::new (S.Context) - PackedAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + S.Diag(Attr.getLoc(), diag::warn_attribute_packed_for_bitfield); + + FD->addAttr(::new (S.Context) PackedAttr( + Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); } else S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); } @@ -1165,10 +1196,12 @@ static bool attrNonNullArgCheck(Sema &S, QualType T, const AttributeList &Attr, SourceRange TypeRange, bool isReturnValue = false) { if (!S.isValidPointerAttrType(T)) { - S.Diag(Attr.getLoc(), isReturnValue - ? diag::warn_attribute_return_pointers_only - : diag::warn_attribute_pointers_only) - << Attr.getName() << AttrParmRange << TypeRange; + if (isReturnValue) + S.Diag(Attr.getLoc(), diag::warn_attribute_return_pointers_only) + << Attr.getName() << AttrParmRange << TypeRange; + else + S.Diag(Attr.getLoc(), diag::warn_attribute_pointers_only) + << Attr.getName() << AttrParmRange << TypeRange << 0; return false; } return true; @@ -1312,6 +1345,17 @@ void Sema::AddAssumeAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E, AssumeAlignedAttr(AttrRange, Context, E, OE, SpellingListIndex)); } +/// Normalize the attribute, __foo__ becomes foo. +/// Returns true if normalization was applied. +static bool normalizeName(StringRef &AttrName) { + if (AttrName.size() > 4 && AttrName.startswith("__") && + AttrName.endswith("__")) { + AttrName = AttrName.drop_front(2).drop_back(2); + return true; + } + return false; +} + static void handleOwnershipAttr(Sema &S, Decl *D, const AttributeList &AL) { // This attribute must be applied to a function declaration. The first // argument to the attribute must be an identifier, the name of the resource, @@ -1353,11 +1397,8 @@ static void handleOwnershipAttr(Sema &S, Decl *D, const AttributeList &AL) { IdentifierInfo *Module = AL.getArgAsIdent(0)->Ident; - // Normalize the argument, __foo__ becomes foo. StringRef ModuleName = Module->getName(); - if (ModuleName.startswith("__") && ModuleName.endswith("__") && - ModuleName.size() > 4) { - ModuleName = ModuleName.drop_front(2).drop_back(2); + if (normalizeName(ModuleName)) { Module = &S.PP.getIdentifierTable().get(ModuleName); } @@ -1519,7 +1560,7 @@ static void handleAliasAttr(Sema &S, Decl *D, const AttributeList &Attr) { } static void handleColdAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (checkAttrMutualExclusion<HotAttr>(S, D, Attr)) + if (checkAttrMutualExclusion<HotAttr>(S, D, Attr.getRange(), Attr.getName())) return; D->addAttr(::new (S.Context) ColdAttr(Attr.getRange(), S.Context, @@ -1527,7 +1568,7 @@ static void handleColdAttr(Sema &S, Decl *D, const AttributeList &Attr) { } static void handleHotAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (checkAttrMutualExclusion<ColdAttr>(S, D, Attr)) + if (checkAttrMutualExclusion<ColdAttr>(S, D, Attr.getRange(), Attr.getName())) return; D->addAttr(::new (S.Context) HotAttr(Attr.getRange(), S.Context, @@ -1569,12 +1610,22 @@ static void handleRestrictAttr(Sema &S, Decl *D, const AttributeList &Attr) { static void handleCommonAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (S.LangOpts.CPlusPlus) { S.Diag(Attr.getLoc(), diag::err_attribute_not_supported_in_lang) - << Attr.getName() << AttributeLangSupport::Cpp; + << Attr.getName() << AttributeLangSupport::Cpp; return; } - D->addAttr(::new (S.Context) CommonAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + if (CommonAttr *CA = S.mergeCommonAttr(D, Attr.getRange(), Attr.getName(), + Attr.getAttributeSpellingListIndex())) + D->addAttr(CA); +} + +static void handleNakedAttr(Sema &S, Decl *D, const AttributeList &Attr) { + if (checkAttrMutualExclusion<DisableTailCallsAttr>(S, D, Attr.getRange(), + Attr.getName())) + return; + + D->addAttr(::new (S.Context) NakedAttr(Attr.getRange(), S.Context, + Attr.getAttributeSpellingListIndex())); } static void handleNoReturnAttr(Sema &S, Decl *D, const AttributeList &attr) { @@ -1613,7 +1664,7 @@ static void handleAnalyzerNoReturnAttr(Sema &S, Decl *D, !VD->getType()->isFunctionPointerType())) { S.Diag(Attr.getLoc(), Attr.isCXX11Attribute() ? diag::err_attribute_wrong_decl_type - : diag::warn_attribute_wrong_decl_type) + : diag::warn_attribute_wrong_decl_type) << Attr.getName() << ExpectedFunctionMethodOrBlock; return; } @@ -1697,6 +1748,26 @@ static void handleDependencyAttr(Sema &S, Scope *Scope, Decl *D, Attr.getAttributeSpellingListIndex())); } +static void handleNotTailCalledAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + if (checkAttrMutualExclusion<AlwaysInlineAttr>(S, D, Attr.getRange(), + Attr.getName())) + return; + + D->addAttr(::new (S.Context) NotTailCalledAttr( + Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); +} + +static void handleDisableTailCallsAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + if (checkAttrMutualExclusion<NakedAttr>(S, D, Attr.getRange(), + Attr.getName())) + return; + + D->addAttr(::new (S.Context) DisableTailCallsAttr( + Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); +} + static void handleUsedAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { if (VD->hasLocalStorage()) { @@ -1825,12 +1896,24 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr(NamedDecl *D, SourceRange Range, VersionTuple Obsoleted, bool IsUnavailable, StringRef Message, - bool Override, + AvailabilityMergeKind AMK, unsigned AttrSpellingListIndex) { VersionTuple MergedIntroduced = Introduced; VersionTuple MergedDeprecated = Deprecated; VersionTuple MergedObsoleted = Obsoleted; bool FoundAny = false; + bool OverrideOrImpl = false; + switch (AMK) { + case AMK_None: + case AMK_Redeclaration: + OverrideOrImpl = false; + break; + + case AMK_Override: + case AMK_ProtocolImplementation: + OverrideOrImpl = true; + break; + } if (D->hasAttrs()) { AttrVec &Attrs = D->getAttrs(); @@ -1847,30 +1930,46 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr(NamedDecl *D, SourceRange Range, continue; } + // If there is an existing availability attribute for this platform that + // is explicit and the new one is implicit use the explicit one and + // discard the new implicit attribute. + if (OldAA->getRange().isValid() && Range.isInvalid()) { + return nullptr; + } + + // If there is an existing attribute for this platform that is implicit + // and the new attribute is explicit then erase the old one and + // continue processing the attributes. + if (Range.isValid() && OldAA->getRange().isInvalid()) { + Attrs.erase(Attrs.begin() + i); + --e; + continue; + } + FoundAny = true; VersionTuple OldIntroduced = OldAA->getIntroduced(); VersionTuple OldDeprecated = OldAA->getDeprecated(); VersionTuple OldObsoleted = OldAA->getObsoleted(); bool OldIsUnavailable = OldAA->getUnavailable(); - if (!versionsMatch(OldIntroduced, Introduced, Override) || - !versionsMatch(Deprecated, OldDeprecated, Override) || - !versionsMatch(Obsoleted, OldObsoleted, Override) || + if (!versionsMatch(OldIntroduced, Introduced, OverrideOrImpl) || + !versionsMatch(Deprecated, OldDeprecated, OverrideOrImpl) || + !versionsMatch(Obsoleted, OldObsoleted, OverrideOrImpl) || !(OldIsUnavailable == IsUnavailable || - (Override && !OldIsUnavailable && IsUnavailable))) { - if (Override) { + (OverrideOrImpl && !OldIsUnavailable && IsUnavailable))) { + if (OverrideOrImpl) { int Which = -1; VersionTuple FirstVersion; VersionTuple SecondVersion; - if (!versionsMatch(OldIntroduced, Introduced, Override)) { + if (!versionsMatch(OldIntroduced, Introduced, OverrideOrImpl)) { Which = 0; FirstVersion = OldIntroduced; SecondVersion = Introduced; - } else if (!versionsMatch(Deprecated, OldDeprecated, Override)) { + } else if (!versionsMatch(Deprecated, OldDeprecated, OverrideOrImpl)) { Which = 1; FirstVersion = Deprecated; SecondVersion = OldDeprecated; - } else if (!versionsMatch(Obsoleted, OldObsoleted, Override)) { + } else if (!versionsMatch(Obsoleted, OldObsoleted, OverrideOrImpl)) { Which = 2; FirstVersion = Obsoleted; SecondVersion = OldObsoleted; @@ -1879,15 +1978,20 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr(NamedDecl *D, SourceRange Range, if (Which == -1) { Diag(OldAA->getLocation(), diag::warn_mismatched_availability_override_unavail) - << AvailabilityAttr::getPrettyPlatformName(Platform->getName()); + << AvailabilityAttr::getPrettyPlatformName(Platform->getName()) + << (AMK == AMK_Override); } else { Diag(OldAA->getLocation(), diag::warn_mismatched_availability_override) << Which << AvailabilityAttr::getPrettyPlatformName(Platform->getName()) - << FirstVersion.getAsString() << SecondVersion.getAsString(); + << FirstVersion.getAsString() << SecondVersion.getAsString() + << (AMK == AMK_Override); } - Diag(Range.getBegin(), diag::note_overridden_method); + if (AMK == AMK_Override) + Diag(Range.getBegin(), diag::note_overridden_method); + else + Diag(Range.getBegin(), diag::note_protocol_method); } else { Diag(OldAA->getLocation(), diag::warn_mismatched_availability); Diag(Range.getBegin(), diag::note_previous_attribute); @@ -1930,11 +2034,11 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr(NamedDecl *D, SourceRange Range, MergedObsoleted == Obsoleted) return nullptr; - // Only create a new attribute if !Override, but we want to do + // Only create a new attribute if !OverrideOrImpl, but we want to do // the checking. if (!checkAvailabilityAttr(*this, Range, Platform, MergedIntroduced, MergedDeprecated, MergedObsoleted) && - !Override) { + !OverrideOrImpl) { return ::new (Context) AvailabilityAttr(Range, Context, Platform, Introduced, Deprecated, Obsoleted, IsUnavailable, Message, @@ -1975,10 +2079,78 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, Deprecated.Version, Obsoleted.Version, IsUnavailable, Str, - /*Override=*/false, + Sema::AMK_None, Index); if (NewAttr) D->addAttr(NewAttr); + + // Transcribe "ios" to "watchos" (and add a new attribute) if the versioning + // matches before the start of the watchOS platform. + if (S.Context.getTargetInfo().getTriple().isWatchOS()) { + IdentifierInfo *NewII = nullptr; + if (II->getName() == "ios") + NewII = &S.Context.Idents.get("watchos"); + else if (II->getName() == "ios_app_extension") + NewII = &S.Context.Idents.get("watchos_app_extension"); + + if (NewII) { + auto adjustWatchOSVersion = [](VersionTuple Version) -> VersionTuple { + if (Version.empty()) + return Version; + auto Major = Version.getMajor(); + auto NewMajor = Major >= 9 ? Major - 7 : 0; + if (NewMajor >= 2) { + if (Version.getMinor().hasValue()) { + if (Version.getSubminor().hasValue()) + return VersionTuple(NewMajor, Version.getMinor().getValue(), + Version.getSubminor().getValue()); + else + return VersionTuple(NewMajor, Version.getMinor().getValue()); + } + } + + return VersionTuple(2, 0); + }; + + auto NewIntroduced = adjustWatchOSVersion(Introduced.Version); + auto NewDeprecated = adjustWatchOSVersion(Deprecated.Version); + auto NewObsoleted = adjustWatchOSVersion(Obsoleted.Version); + + AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(ND, + SourceRange(), + NewII, + NewIntroduced, + NewDeprecated, + NewObsoleted, + IsUnavailable, Str, + Sema::AMK_None, + Index); + if (NewAttr) + D->addAttr(NewAttr); + } + } else if (S.Context.getTargetInfo().getTriple().isTvOS()) { + // Transcribe "ios" to "tvos" (and add a new attribute) if the versioning + // matches before the start of the tvOS platform. + IdentifierInfo *NewII = nullptr; + if (II->getName() == "ios") + NewII = &S.Context.Idents.get("tvos"); + else if (II->getName() == "ios_app_extension") + NewII = &S.Context.Idents.get("tvos_app_extension"); + + if (NewII) { + AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(ND, + SourceRange(), + NewII, + Introduced.Version, + Deprecated.Version, + Obsoleted.Version, + IsUnavailable, Str, + Sema::AMK_None, + Index); + if (NewAttr) + D->addAttr(NewAttr); + } + } } template <class T> @@ -2492,17 +2664,17 @@ static void handleFormatArgAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (!checkFunctionOrMethodParameterIndex(S, D, Attr, 1, IdxExpr, Idx)) return; - // make sure the format string is really a string + // Make sure the format string is really a string. QualType Ty = getFunctionOrMethodParamType(D, Idx); - bool not_nsstring_type = !isNSStringType(Ty, S.Context); - if (not_nsstring_type && + bool NotNSStringTy = !isNSStringType(Ty, S.Context); + if (NotNSStringTy && !isCFStringType(Ty, S.Context) && (!Ty->isPointerType() || !Ty->getAs<PointerType>()->getPointeeType()->isCharType())) { S.Diag(Attr.getLoc(), diag::err_format_attribute_not) - << (not_nsstring_type ? "a string type" : "an NSString") - << IdxExpr->getSourceRange() << getFunctionOrMethodParamRange(D, 0); + << "a string type" << IdxExpr->getSourceRange() + << getFunctionOrMethodParamRange(D, 0); return; } Ty = getFunctionOrMethodResultType(D); @@ -2511,7 +2683,7 @@ static void handleFormatArgAttr(Sema &S, Decl *D, const AttributeList &Attr) { (!Ty->isPointerType() || !Ty->getAs<PointerType>()->getPointeeType()->isCharType())) { S.Diag(Attr.getLoc(), diag::err_format_attribute_result_not) - << (not_nsstring_type ? "string type" : "NSString") + << (NotNSStringTy ? "string type" : "NSString") << IdxExpr->getSourceRange() << getFunctionOrMethodParamRange(D, 0); return; } @@ -2588,7 +2760,7 @@ static void handleInitPriorityAttr(Sema &S, Decl *D, if (prioritynum < 101 || prioritynum > 65535) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_outof_range) - << E->getSourceRange(); + << E->getSourceRange() << Attr.getName() << 101 << 65535; Attr.setInvalid(); return; } @@ -2635,9 +2807,7 @@ static void handleFormatAttr(Sema &S, Decl *D, const AttributeList &Attr) { IdentifierInfo *II = Attr.getArgAsIdent(0)->Ident; StringRef Format = II->getName(); - // Normalize the argument, __foo__ becomes foo. - if (Format.startswith("__") && Format.endswith("__")) { - Format = Format.substr(2, Format.size() - 4); + if (normalizeName(Format)) { // If we've modified the string name, we need a new identifier for it. II = &S.Context.Idents.get(Format); } @@ -2858,7 +3028,7 @@ void Sema::AddAlignValueAttr(SourceRange AttrRange, Decl *D, Expr *E, } if (!E->isValueDependent()) { - llvm::APSInt Alignment(32); + llvm::APSInt Alignment; ExprResult ICE = VerifyIntegerConstantExpression(E, &Alignment, diag::err_align_value_attribute_argument_not_int, @@ -2972,7 +3142,7 @@ void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E, } // FIXME: Cache the number on the Attr object? - llvm::APSInt Alignment(32); + llvm::APSInt Alignment; ExprResult ICE = VerifyIntegerConstantExpression(E, &Alignment, diag::err_aligned_attribute_argument_not_int, @@ -2980,42 +3150,44 @@ void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E, if (ICE.isInvalid()) return; + uint64_t AlignVal = Alignment.getZExtValue(); + // C++11 [dcl.align]p2: // -- if the constant expression evaluates to zero, the alignment // specifier shall have no effect // C11 6.7.5p6: // An alignment specification of zero has no effect. if (!(TmpAttr.isAlignas() && !Alignment)) { - if(!llvm::isPowerOf2_64(Alignment.getZExtValue())) { + if (!llvm::isPowerOf2_64(AlignVal)) { Diag(AttrLoc, diag::err_alignment_not_power_of_two) << E->getSourceRange(); return; } - if (Context.getTargetInfo().isTLSSupported()) { - if (unsigned MaxAlign = Context.getTargetInfo().getMaxTLSAlign()) { - if (VarDecl *VD = dyn_cast<VarDecl>(D)) { - if (VD->getTLSKind()) { - CharUnits MaxAlignChars = Context.toCharUnitsFromBits(MaxAlign); - if (Alignment.getSExtValue() > MaxAlignChars.getQuantity()) { - Diag(VD->getLocation(), diag::err_tls_var_aligned_over_maximum) - << (unsigned)Alignment.getZExtValue() << VD - << (unsigned)MaxAlignChars.getQuantity(); - return; - } - } - } - } - } } // Alignment calculations can wrap around if it's greater than 2**28. - unsigned MaxValidAlignment = TmpAttr.isDeclspec() ? 8192 : 268435456; - if (Alignment.getZExtValue() > MaxValidAlignment) { + unsigned MaxValidAlignment = + Context.getTargetInfo().getTriple().isOSBinFormatCOFF() ? 8192 + : 268435456; + if (AlignVal > MaxValidAlignment) { Diag(AttrLoc, diag::err_attribute_aligned_too_great) << MaxValidAlignment << E->getSourceRange(); return; } + if (Context.getTargetInfo().isTLSSupported()) { + unsigned MaxTLSAlign = + Context.toCharUnitsFromBits(Context.getTargetInfo().getMaxTLSAlign()) + .getQuantity(); + auto *VD = dyn_cast<VarDecl>(D); + if (MaxTLSAlign && AlignVal > MaxTLSAlign && VD && + VD->getTLSKind() != VarDecl::TLS_None) { + Diag(VD->getLocation(), diag::err_tls_var_aligned_over_maximum) + << (unsigned)AlignVal << VD << MaxTLSAlign; + return; + } + } + AlignedAttr *AA = ::new (Context) AlignedAttr(AttrRange, Context, true, ICE.get(), SpellingListIndex); AA->setPackExpansion(IsPackExpansion); @@ -3098,40 +3270,31 @@ bool Sema::checkMSInheritanceAttrOnDefinition( return true; } -/// handleModeAttr - This attribute modifies the width of a decl with primitive -/// type. -/// -/// Despite what would be logical, the mode attribute is a decl attribute, not a -/// type attribute: 'int ** __attribute((mode(HI))) *G;' tries to make 'G' be -/// HImode, not an intermediate pointer. -static void handleModeAttr(Sema &S, Decl *D, const AttributeList &Attr) { - // This attribute isn't documented, but glibc uses it. It changes - // the width of an int or unsigned int to the specified size. - if (!Attr.isArgIdent(0)) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) << Attr.getName() - << AANT_ArgumentIdentifier; - return; - } - - IdentifierInfo *Name = Attr.getArgAsIdent(0)->Ident; - StringRef Str = Name->getName(); - - // Normalize the attribute name, __foo__ becomes foo. - if (Str.startswith("__") && Str.endswith("__")) - Str = Str.substr(2, Str.size() - 4); - - unsigned DestWidth = 0; - bool IntegerMode = true; - bool ComplexMode = false; +/// parseModeAttrArg - Parses attribute mode string and returns parsed type +/// attribute. +static void parseModeAttrArg(Sema &S, StringRef Str, unsigned &DestWidth, + bool &IntegerMode, bool &ComplexMode) { switch (Str.size()) { case 2: switch (Str[0]) { - case 'Q': DestWidth = 8; break; - case 'H': DestWidth = 16; break; - case 'S': DestWidth = 32; break; - case 'D': DestWidth = 64; break; - case 'X': DestWidth = 96; break; - case 'T': DestWidth = 128; break; + case 'Q': + DestWidth = 8; + break; + case 'H': + DestWidth = 16; + break; + case 'S': + DestWidth = 32; + break; + case 'D': + DestWidth = 64; + break; + case 'X': + DestWidth = 96; + break; + case 'T': + DestWidth = 128; + break; } if (Str[1] == 'F') { IntegerMode = false; @@ -3159,6 +3322,52 @@ static void handleModeAttr(Sema &S, Decl *D, const AttributeList &Attr) { DestWidth = S.Context.getTargetInfo().getUnwindWordWidth(); break; } +} + +/// handleModeAttr - This attribute modifies the width of a decl with primitive +/// type. +/// +/// Despite what would be logical, the mode attribute is a decl attribute, not a +/// type attribute: 'int ** __attribute((mode(HI))) *G;' tries to make 'G' be +/// HImode, not an intermediate pointer. +static void handleModeAttr(Sema &S, Decl *D, const AttributeList &Attr) { + // This attribute isn't documented, but glibc uses it. It changes + // the width of an int or unsigned int to the specified size. + if (!Attr.isArgIdent(0)) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) << Attr.getName() + << AANT_ArgumentIdentifier; + return; + } + + IdentifierInfo *Name = Attr.getArgAsIdent(0)->Ident; + StringRef Str = Name->getName(); + + normalizeName(Str); + + unsigned DestWidth = 0; + bool IntegerMode = true; + bool ComplexMode = false; + llvm::APInt VectorSize(64, 0); + if (Str.size() >= 4 && Str[0] == 'V') { + // Minimal length of vector mode is 4: 'V' + NUMBER(>=1) + TYPE(>=2). + size_t StrSize = Str.size(); + size_t VectorStringLength = 0; + while ((VectorStringLength + 1) < StrSize && + isdigit(Str[VectorStringLength + 1])) + ++VectorStringLength; + if (VectorStringLength && + !Str.substr(1, VectorStringLength).getAsInteger(10, VectorSize) && + VectorSize.isPowerOf2()) { + parseModeAttrArg(S, Str.substr(VectorStringLength + 1), DestWidth, + IntegerMode, ComplexMode); + S.Diag(Attr.getLoc(), diag::warn_vector_mode_deprecated); + } else { + VectorSize = 0; + } + } + + if (!VectorSize) + parseModeAttrArg(S, Str, DestWidth, IntegerMode, ComplexMode); QualType OldTy; if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) @@ -3217,7 +3426,10 @@ static void handleModeAttr(Sema &S, Decl *D, const AttributeList &Attr) { } QualType NewTy = NewElemTy; - if (const VectorType *OldVT = OldTy->getAs<VectorType>()) { + if (VectorSize.getBoolValue()) { + NewTy = S.Context.getVectorType(NewTy, VectorSize.getZExtValue(), + VectorType::GenericVector); + } else if (const VectorType *OldVT = OldTy->getAs<VectorType>()) { // Complex machine mode does not support base vector types. if (ComplexMode) { S.Diag(Attr.getLoc(), diag::err_complex_mode_vector_type); @@ -3280,6 +3492,42 @@ AlwaysInlineAttr *Sema::mergeAlwaysInlineAttr(Decl *D, SourceRange Range, AttrSpellingListIndex); } +CommonAttr *Sema::mergeCommonAttr(Decl *D, SourceRange Range, + IdentifierInfo *Ident, + unsigned AttrSpellingListIndex) { + if (checkAttrMutualExclusion<InternalLinkageAttr>(*this, D, Range, Ident)) + return nullptr; + + return ::new (Context) CommonAttr(Range, Context, AttrSpellingListIndex); +} + +InternalLinkageAttr * +Sema::mergeInternalLinkageAttr(Decl *D, SourceRange Range, + IdentifierInfo *Ident, + unsigned AttrSpellingListIndex) { + if (auto VD = dyn_cast<VarDecl>(D)) { + // Attribute applies to Var but not any subclass of it (like ParmVar, + // ImplicitParm or VarTemplateSpecialization). + if (VD->getKind() != Decl::Var) { + Diag(Range.getBegin(), diag::warn_attribute_wrong_decl_type) + << Ident << (getLangOpts().CPlusPlus ? ExpectedFunctionVariableOrClass + : ExpectedVariableOrFunction); + return nullptr; + } + // Attribute does not apply to non-static local variables. + if (VD->hasLocalStorage()) { + Diag(VD->getLocation(), diag::warn_internal_linkage_local_storage); + return nullptr; + } + } + + if (checkAttrMutualExclusion<CommonAttr>(*this, D, Range, Ident)) + return nullptr; + + return ::new (Context) + InternalLinkageAttr(Range, Context, AttrSpellingListIndex); +} + MinSizeAttr *Sema::mergeMinSizeAttr(Decl *D, SourceRange Range, unsigned AttrSpellingListIndex) { if (OptimizeNoneAttr *Optnone = D->getAttr<OptimizeNoneAttr>()) { @@ -3316,6 +3564,10 @@ OptimizeNoneAttr *Sema::mergeOptimizeNoneAttr(Decl *D, SourceRange Range, static void handleAlwaysInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) { + if (checkAttrMutualExclusion<NotTailCalledAttr>(S, D, Attr.getRange(), + Attr.getName())) + return; + if (AlwaysInlineAttr *Inline = S.mergeAlwaysInlineAttr( D, Attr.getRange(), Attr.getName(), Attr.getAttributeSpellingListIndex())) @@ -3349,6 +3601,7 @@ static void handleGlobalAttr(Sema &S, Decl *D, const AttributeList &Attr) { D->addAttr(::new (S.Context) CUDAGlobalAttr(Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + } static void handleGNUInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) { @@ -3645,7 +3898,7 @@ static void handleArgumentWithTypeTagAttr(Sema &S, Decl *D, QualType BufferTy = getFunctionOrMethodParamType(D, ArgumentIdx); if (!BufferTy->isPointerType()) { S.Diag(Attr.getLoc(), diag::err_attribute_pointers_only) - << Attr.getName(); + << Attr.getName() << 0; } } @@ -3898,7 +4151,8 @@ static void handleObjCRequiresSuperAttr(Sema &S, Decl *D, static void handleCFAuditedTransferAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (checkAttrMutualExclusion<CFUnknownTransferAttr>(S, D, Attr)) + if (checkAttrMutualExclusion<CFUnknownTransferAttr>(S, D, Attr.getRange(), + Attr.getName())) return; D->addAttr(::new (S.Context) @@ -3908,7 +4162,8 @@ static void handleCFAuditedTransferAttr(Sema &S, Decl *D, static void handleCFUnknownTransferAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (checkAttrMutualExclusion<CFAuditedTransferAttr>(S, D, Attr)) + if (checkAttrMutualExclusion<CFAuditedTransferAttr>(S, D, Attr.getRange(), + Attr.getName())) return; D->addAttr(::new (S.Context) @@ -4231,14 +4486,86 @@ static void handleMSP430InterruptAttr(Sema &S, Decl *D, D->addAttr(UsedAttr::CreateImplicit(S.Context)); } +static void handleMipsInterruptAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + // Only one optional argument permitted. + if (Attr.getNumArgs() > 1) { + S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) + << Attr.getName() << 1; + return; + } + + StringRef Str; + SourceLocation ArgLoc; + + if (Attr.getNumArgs() == 0) + Str = ""; + else if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str, &ArgLoc)) + return; + + // Semantic checks for a function with the 'interrupt' attribute for MIPS: + // a) Must be a function. + // b) Must have no parameters. + // c) Must have the 'void' return type. + // d) Cannot have the 'mips16' attribute, as that instruction set + // lacks the 'eret' instruction. + // e) The attribute itself must either have no argument or one of the + // valid interrupt types, see [MipsInterruptDocs]. + + if (!isFunctionOrMethod(D)) { + S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) + << "'interrupt'" << ExpectedFunctionOrMethod; + return; + } + + if (hasFunctionProto(D) && getFunctionOrMethodNumParams(D) != 0) { + S.Diag(D->getLocation(), diag::warn_mips_interrupt_attribute) + << 0; + return; + } + + if (!getFunctionOrMethodResultType(D)->isVoidType()) { + S.Diag(D->getLocation(), diag::warn_mips_interrupt_attribute) + << 1; + return; + } + + if (checkAttrMutualExclusion<Mips16Attr>(S, D, Attr.getRange(), + Attr.getName())) + return; + + MipsInterruptAttr::InterruptType Kind; + if (!MipsInterruptAttr::ConvertStrToInterruptType(Str, Kind)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported) + << Attr.getName() << "'" + std::string(Str) + "'"; + return; + } + + D->addAttr(::new (S.Context) MipsInterruptAttr( + Attr.getLoc(), S.Context, Kind, Attr.getAttributeSpellingListIndex())); +} + static void handleInterruptAttr(Sema &S, Decl *D, const AttributeList &Attr) { // Dispatch the interrupt attribute based on the current target. if (S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::msp430) handleMSP430InterruptAttr(S, D, Attr); + else if (S.Context.getTargetInfo().getTriple().getArch() == + llvm::Triple::mipsel || + S.Context.getTargetInfo().getTriple().getArch() == + llvm::Triple::mips) + handleMipsInterruptAttr(S, D, Attr); else handleARMInterruptAttr(S, D, Attr); } +static void handleMips16Attribute(Sema &S, Decl *D, const AttributeList &Attr) { + if (checkAttrMutualExclusion<MipsInterruptAttr>(S, D, Attr.getRange(), + Attr.getName())) + return; + + handleSimpleAttribute<Mips16Attr>(S, D, Attr); +} + static void handleAMDGPUNumVGPRAttr(Sema &S, Decl *D, const AttributeList &Attr) { uint32_t NumRegs; @@ -4334,6 +4661,14 @@ static void handleDLLAttr(Sema &S, Decl *D, const AttributeList &A) { } } + if (auto *MD = dyn_cast<CXXMethodDecl>(D)) { + if (S.Context.getTargetInfo().getCXXABI().isMicrosoft() && + MD->getParent()->isLambda()) { + S.Diag(A.getRange().getBegin(), diag::err_attribute_dll_lambda) << A.getName(); + return; + } + } + unsigned Index = A.getAttributeSpellingListIndex(); Attr *NewAttr = A.getKind() == AttributeList::AT_DLLExport ? (Attr *)S.mergeDLLExportAttr(D, A.getRange(), Index) @@ -4509,8 +4844,10 @@ static void handleNoSanitizeAttr(Sema &S, Decl *D, const AttributeList &Attr) { static void handleNoSanitizeSpecificAttr(Sema &S, Decl *D, const AttributeList &Attr) { + StringRef AttrName = Attr.getName()->getName(); + normalizeName(AttrName); std::string SanitizerName = - llvm::StringSwitch<std::string>(Attr.getName()->getName()) + llvm::StringSwitch<std::string>(AttrName) .Case("no_address_safety_analysis", "address") .Case("no_sanitize_address", "address") .Case("no_sanitize_thread", "thread") @@ -4520,6 +4857,14 @@ static void handleNoSanitizeSpecificAttr(Sema &S, Decl *D, Attr.getAttributeSpellingListIndex())); } +static void handleInternalLinkageAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + if (InternalLinkageAttr *Internal = + S.mergeInternalLinkageAttr(D, Attr.getRange(), Attr.getName(), + Attr.getAttributeSpellingListIndex())) + D->addAttr(Internal); +} + /// Handles semantic checking for features that are common to all attributes, /// such as checking whether a parameter was properly specified, or the correct /// number of arguments were passed, etc. @@ -4583,7 +4928,7 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, // which do not apply to the current target architecture are treated as // though they were unknown attributes. if (Attr.getKind() == AttributeList::UnknownAttribute || - !Attr.existsInTarget(S.Context.getTargetInfo().getTriple())) { + !Attr.existsInTarget(S.Context.getTargetInfo())) { S.Diag(Attr.getLoc(), Attr.isDeclspecAttribute() ? diag::warn_unhandled_ms_attribute_ignored : diag::warn_unknown_attribute_ignored) @@ -4610,7 +4955,7 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, handleDLLAttr(S, D, Attr); break; case AttributeList::AT_Mips16: - handleSimpleAttribute<Mips16Attr>(S, D, Attr); + handleMips16Attribute(S, D, Attr); break; case AttributeList::AT_NoMips16: handleSimpleAttribute<NoMips16Attr>(S, D, Attr); @@ -4663,6 +5008,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_CUDAConstant: handleSimpleAttribute<CUDAConstantAttr>(S, D, Attr); break; + case AttributeList::AT_PassObjectSize: + handlePassObjectSizeAttr(S, D, Attr); + break; case AttributeList::AT_Constructor: handleConstructorAttr(S, D, Attr); break; @@ -4723,6 +5071,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_Mode: handleModeAttr(S, D, Attr); break; + case AttributeList::AT_NoAlias: + handleSimpleAttribute<NoAliasAttr>(S, D, Attr); + break; case AttributeList::AT_NoCommon: handleSimpleAttribute<NoCommonAttr>(S, D, Attr); break; @@ -4754,7 +5105,7 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, handleHotAttr(S, D, Attr); break; case AttributeList::AT_Naked: - handleSimpleAttribute<NakedAttr>(S, D, Attr); + handleNakedAttr(S, D, Attr); break; case AttributeList::AT_NoReturn: handleNoReturnAttr(S, D, Attr); @@ -4874,6 +5225,12 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_ReturnsTwice: handleSimpleAttribute<ReturnsTwiceAttr>(S, D, Attr); break; + case AttributeList::AT_NotTailCalled: + handleNotTailCalledAttr(S, D, Attr); + break; + case AttributeList::AT_DisableTailCalls: + handleDisableTailCallsAttr(S, D, Attr); + break; case AttributeList::AT_Used: handleUsedAttr(S, D, Attr); break; @@ -4958,6 +5315,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_OpenCLImageAccess: handleSimpleAttribute<OpenCLImageAccessAttr>(S, D, Attr); break; + case AttributeList::AT_InternalLinkage: + handleInternalLinkageAttr(S, D, Attr); + break; // Microsoft attributes: case AttributeList::AT_MSNoVTable: @@ -5299,26 +5659,50 @@ void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD) { } /// Is the given declaration allowed to use a forbidden type? -static bool isForbiddenTypeAllowed(Sema &S, Decl *decl) { +/// If so, it'll still be annotated with an attribute that makes it +/// illegal to actually use. +static bool isForbiddenTypeAllowed(Sema &S, Decl *decl, + const DelayedDiagnostic &diag, + UnavailableAttr::ImplicitReason &reason) { // Private ivars are always okay. Unfortunately, people don't // always properly make their ivars private, even in system headers. // Plus we need to make fields okay, too. - // Function declarations in sys headers will be marked unavailable. if (!isa<FieldDecl>(decl) && !isa<ObjCPropertyDecl>(decl) && !isa<FunctionDecl>(decl)) return false; - // Require it to be declared in a system header. - return S.Context.getSourceManager().isInSystemHeader(decl->getLocation()); + // Silently accept unsupported uses of __weak in both user and system + // declarations when it's been disabled, for ease of integration with + // -fno-objc-arc files. We do have to take some care against attempts + // to define such things; for now, we've only done that for ivars + // and properties. + if ((isa<ObjCIvarDecl>(decl) || isa<ObjCPropertyDecl>(decl))) { + if (diag.getForbiddenTypeDiagnostic() == diag::err_arc_weak_disabled || + diag.getForbiddenTypeDiagnostic() == diag::err_arc_weak_no_runtime) { + reason = UnavailableAttr::IR_ForbiddenWeak; + return true; + } + } + + // Allow all sorts of things in system headers. + if (S.Context.getSourceManager().isInSystemHeader(decl->getLocation())) { + // Currently, all the failures dealt with this way are due to ARC + // restrictions. + reason = UnavailableAttr::IR_ARCForbiddenType; + return true; + } + + return false; } /// Handle a delayed forbidden-type diagnostic. static void handleDelayedForbiddenType(Sema &S, DelayedDiagnostic &diag, Decl *decl) { - if (decl && isForbiddenTypeAllowed(S, decl)) { - decl->addAttr(UnavailableAttr::CreateImplicit(S.Context, - "this system declaration uses an unsupported type", - diag.Loc)); + auto reason = UnavailableAttr::IR_None; + if (decl && isForbiddenTypeAllowed(S, decl, diag, reason)) { + assert(reason && "didn't set reason?"); + decl->addAttr(UnavailableAttr::CreateImplicit(S.Context, "", reason, + diag.Loc)); return; } if (S.getLangOpts().ObjCAutoRefCount) @@ -5371,6 +5755,7 @@ static void DoEmitAvailabilityWarning(Sema &S, Sema::AvailabilityDiagnostic K, bool ObjCPropertyAccess) { // Diagnostics for deprecated or unavailable. unsigned diag, diag_message, diag_fwdclass_message; + unsigned diag_available_here = diag::note_availability_specified_here; // Matches 'diag::note_property_attribute' options. unsigned property_note_select; @@ -5400,6 +5785,50 @@ static void DoEmitAvailabilityWarning(Sema &S, Sema::AvailabilityDiagnostic K, diag_fwdclass_message = diag::warn_unavailable_fwdclass_message; property_note_select = /* unavailable */ 1; available_here_select_kind = /* unavailable */ 0; + + if (auto attr = D->getAttr<UnavailableAttr>()) { + if (attr->isImplicit() && attr->getImplicitReason()) { + // Most of these failures are due to extra restrictions in ARC; + // reflect that in the primary diagnostic when applicable. + auto flagARCError = [&] { + if (S.getLangOpts().ObjCAutoRefCount && + S.getSourceManager().isInSystemHeader(D->getLocation())) + diag = diag::err_unavailable_in_arc; + }; + + switch (attr->getImplicitReason()) { + case UnavailableAttr::IR_None: break; + + case UnavailableAttr::IR_ARCForbiddenType: + flagARCError(); + diag_available_here = diag::note_arc_forbidden_type; + break; + + case UnavailableAttr::IR_ForbiddenWeak: + if (S.getLangOpts().ObjCWeakRuntime) + diag_available_here = diag::note_arc_weak_disabled; + else + diag_available_here = diag::note_arc_weak_no_runtime; + break; + + case UnavailableAttr::IR_ARCForbiddenConversion: + flagARCError(); + diag_available_here = diag::note_performs_forbidden_arc_conversion; + break; + + case UnavailableAttr::IR_ARCInitReturnsUnrelated: + flagARCError(); + diag_available_here = diag::note_arc_init_returns_unrelated; + break; + + case UnavailableAttr::IR_ARCFieldWithOwnership: + flagARCError(); + diag_available_here = diag::note_arc_field_with_ownership; + break; + } + } + } + break; case Sema::AD_Partial: @@ -5426,7 +5855,7 @@ static void DoEmitAvailabilityWarning(Sema &S, Sema::AvailabilityDiagnostic K, S.Diag(UnknownObjCClass->getLocation(), diag::note_forward_class); } - S.Diag(D->getLocation(), diag::note_availability_specified_here) + S.Diag(D->getLocation(), diag_available_here) << D << available_here_select_kind; if (K == Sema::AD_Partial) S.Diag(Loc, diag::note_partial_availability_silence) << D; |