diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -2030,6 +2030,10 @@ /// /// This does not determine whether the function has been defined (e.g., in a /// previous definition); for that information, use isDefined. + /// + /// Note: the function declaration does not become a definition until the + /// parser reaches the definition, if called before, this function will return + /// `false`. bool isThisDeclarationADefinition() const { return isDeletedAsWritten() || isDefaulted() || Body || hasSkippedBody() || isLateTemplateParsed() || willHaveBody() || hasDefiningAttr(); diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -3420,3 +3420,10 @@ let Subjects = SubjectList<[NonParmVar, Function, Block, ObjCMethod]>; let Documentation = [ObjCExternallyRetainedDocs]; } + +def NoBuiltin : Attr { + let Spellings = [Clang<"no_builtin">]; + let Args = [VariadicStringArgument<"BuiltinNames">]; + let Subjects = SubjectList<[Function]>; + let Documentation = [NoBuiltinDocs]; +} diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -4391,3 +4391,38 @@ }]; } + +def NoBuiltinDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +.. Note:: This attribute is not yet fully implemented, it is validated but has +no effect on the generated code. + +The ``__attribute__((no_builtin))`` is similar to the ``-fno-builtin`` flag +except it is specific to the body of a function. The attribute may also be +applied to a virtual function but has no effect on the behavior of overriding +functions in a derived class. + +It accepts one or more strings corresponding to the name of the builtin +(e.g. "memcpy", "memset") or "*" which disables all builtins at once. + +.. code-block:: c++ + + // The compiler is not allowed to add any builtin to foo's body. + void foo(char* data, size_t count) __attribute__((no_builtin("*"))) { + // The compiler is not allowed to convert the loop into + // `__builtin_memset(data, 0xFE, count);`. + for (size_t i = 0; i < count; ++i) + data[i] = 0xFE; + } + + // The compiler is not allowed to add the `memcpy` builtin to bar's body. + void bar(char* data, size_t count) __attribute__((no_builtin("memcpy"))) { + // The compiler is allowed to convert the loop into + // `__builtin_memset(data, 0xFE, count);` but cannot generate any + // `__builtin_memcpy` + for (size_t i = 0; i < count; ++i) + data[i] = 0xFE; + } + }]; +} diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -3604,6 +3604,15 @@ def err_attribute_overloadable_multiple_unmarked_overloads : Error< "at most one overload for a given name may lack the 'overloadable' " "attribute">; +def warn_attribute_no_builtin_invalid_builtin_name : Warning< + "'%0' is not a valid builtin name for %1">, + InGroup; // Which group should it be in? +def err_attribute_no_builtin_wildcard_or_builtin_name : Error< + "empty %0 cannot be composed with named ones">; +def err_attribute_no_builtin_on_non_definition : Error< + "%0 attribute is permitted on definitions only">; +def err_attribute_no_builtin_on_defaulted_deleted_function : Error< + "%0 attribute has no effect on defaulted or deleted functions">; def warn_ns_attribute_wrong_return_type : Warning< "%0 attribute only applies to %select{functions|methods|properties}1 that " "return %select{an Objective-C object|a pointer|a non-retainable pointer}2">, diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -1849,6 +1849,18 @@ FuncAttrs.addAttribute(llvm::Attribute::NoDuplicate); if (TargetDecl->hasAttr()) FuncAttrs.addAttribute(llvm::Attribute::Convergent); + if (const auto *Attr = TargetDecl->getAttr()) { + bool HasWildcard = llvm::is_contained(Attr->builtinNames(), "*"); + if (HasWildcard) + FuncAttrs.addAttribute("no-builtins"); + else + for (StringRef BuiltinName : Attr->builtinNames()) { + SmallString<32> AttributeName; + AttributeName += "no-builtin-"; + AttributeName += BuiltinName; + FuncAttrs.addAttribute(AttributeName); + } + } if (const FunctionDecl *Fn = dyn_cast(TargetDecl)) { AddAttributesFromFunctionProtoType( diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -9551,6 +9551,29 @@ } } + // Diagnose no_builtin attribute on function declaration that are not a + // definition. + // FIXME: We should really be doing this in + // SemaDeclAttr.cpp::handleNoBuiltinAttr, unfortunately we only have access to + // the FunctionDecl and at this point of the code + // FunctionDecl::isThisDeclarationADefinition() which always returns `false` + // because Sema::ActOnStartOfFunctionDef has not been called yet. + if (const auto *NBA = NewFD->getAttr()) + switch (D.getFunctionDefinitionKind()) { + case FDK_Defaulted: + case FDK_Deleted: + Diag(NBA->getLocation(), + diag::err_attribute_no_builtin_on_defaulted_deleted_function) + << NBA->getSpelling(); + break; + case FDK_Declaration: + Diag(NBA->getLocation(), diag::err_attribute_no_builtin_on_non_definition) + << NBA->getSpelling(); + break; + case FDK_Definition: + break; + } + return NewFD; } diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -40,11 +40,7 @@ using namespace sema; namespace AttributeLangSupport { - enum LANG { - C, - Cpp, - ObjC - }; +enum LANG { C, Cpp, ObjC }; } // end namespace AttributeLangSupport //===----------------------------------------------------------------------===// @@ -68,8 +64,8 @@ /// been processed by Sema::GetTypeForDeclarator. static bool hasDeclarator(const Decl *D) { // In some sense, TypedefDecl really *ought* to be a DeclaratorDecl. - return isa(D) || isa(D) || isa(D) || - isa(D); + return isa(D) || isa(D) || + isa(D) || isa(D); } /// hasFunctionProto - Return true if the given decl has a argument @@ -155,7 +151,7 @@ if (!Cls) return false; - IdentifierInfo* ClsName = Cls->getIdentifier(); + IdentifierInfo *ClsName = Cls->getIdentifier(); // FIXME: Should we walk the chain of classes? return ClsName == &Ctx.Idents.get("NSString") || @@ -207,9 +203,8 @@ /// output an error. static bool checkAttributeAtLeastNumArgs(Sema &S, const ParsedAttr &AL, unsigned Num) { - return checkAttributeNumArgsImpl(S, AL, Num, - diag::err_attribute_too_few_arguments, - std::less()); + return checkAttributeNumArgsImpl( + S, AL, Num, diag::err_attribute_too_few_arguments, std::less()); } /// Check if the attribute has at most as many args as Num. May @@ -273,8 +268,9 @@ /// that the result will fit into a regular (signed) int. All args have the same /// purpose as they do in checkUInt32Argument. template -static bool checkPositiveIntArgument(Sema &S, const AttrInfo &AI, const Expr *Expr, - int &Val, unsigned Idx = UINT_MAX) { +static bool checkPositiveIntArgument(Sema &S, const AttrInfo &AI, + const Expr *Expr, int &Val, + unsigned Idx = UINT_MAX) { uint32_t UVal; if (!checkUInt32Argument(S, AI, Expr, UVal, Idx)) return false; @@ -306,8 +302,8 @@ template static bool checkAttrMutualExclusion(Sema &S, Decl *D, const Attr &AL) { if (const auto *A = D->getAttr()) { - S.Diag(AL.getLocation(), diag::err_attributes_are_not_compatible) << &AL - << A; + S.Diag(AL.getLocation(), diag::err_attributes_are_not_compatible) + << &AL << A; S.Diag(A->getLocation(), diag::note_conflicting_attribute); return true; } @@ -404,13 +400,13 @@ } template -static const Sema::SemaDiagnosticBuilder& +static const Sema::SemaDiagnosticBuilder & appendDiagnostics(const Sema::SemaDiagnosticBuilder &Bldr) { return Bldr; } template -static const Sema::SemaDiagnosticBuilder& +static const Sema::SemaDiagnosticBuilder & appendDiagnostics(const Sema::SemaDiagnosticBuilder &Bldr, T &&ExtraArg, DiagnosticArgs &&... ExtraArgs) { return appendDiagnostics(Bldr << std::forward(ExtraArg), @@ -458,10 +454,9 @@ return QT->isBooleanType() || QT->isIntegerType(); } - // Check to see if the type is a smart pointer of some kind. We assume // it's a smart pointer if it defines both operator-> and operator*. -static bool threadSafetyCheckIsSmartPointer(Sema &S, const RecordType* RT) { +static bool threadSafetyCheckIsSmartPointer(Sema &S, const RecordType *RT) { auto IsOverloadedOperatorPresent = [&S](const RecordDecl *Record, OverloadedOperatorKind Op) { DeclContextLookupResult Result = @@ -688,10 +683,10 @@ const RecordType *RT = getRecordType(ArgTy); // Now check if we index into a record type function param. - if(!RT && ParamIdxOk) { + if (!RT && ParamIdxOk) { const auto *FD = dyn_cast(D); const auto *IL = dyn_cast(ArgExp); - if(FD && IL) { + if (FD && IL) { unsigned int NumParams = FD->getNumParams(); llvm::APInt ArgValue = IL->getValue(); uint64_t ParamIdxFromOne = ArgValue.getZExtValue(); @@ -914,7 +909,7 @@ static void handleSharedTrylockFunctionAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - SmallVector Args; + SmallVector Args; if (!checkTryLockFunAttrCommon(S, D, AL, Args)) return; @@ -924,7 +919,7 @@ static void handleExclusiveTrylockFunctionAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - SmallVector Args; + SmallVector Args; if (!checkTryLockFunAttrCommon(S, D, AL, Args)) return; @@ -934,7 +929,7 @@ static void handleLockReturnedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // check that the argument is lockable object - SmallVector Args; + SmallVector Args; checkAttrArgsAreCapabilityObjs(S, D, AL, Args); unsigned Size = Args.size(); if (Size == 0) @@ -948,7 +943,7 @@ return; // check that all arguments are lockable objects - SmallVector Args; + SmallVector Args; checkAttrArgsAreCapabilityObjs(S, D, AL, Args); unsigned Size = Args.size(); if (Size == 0) @@ -1040,7 +1035,7 @@ return true; } }; -} +} // namespace static void handleDiagnoseIfAttr(Sema &S, Decl *D, const ParsedAttr &AL) { S.Diag(AL.getLoc(), diag::ext_clang_diagnose_if); @@ -1068,6 +1063,56 @@ S.Context, AL, Cond, Msg, DiagType, ArgDependent, cast(D))); } +static void handleNoBuiltinAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + static constexpr const StringRef kWildcard = "*"; + + llvm::SmallVector Names; + bool HasWildcard = false; + + const auto AddBuiltinName = [&Names, &HasWildcard](StringRef Name) { + if (Name == kWildcard) + HasWildcard = true; + Names.push_back(Name); + }; + + // Add previously defined attributes. + if (const auto *NBA = D->getAttr()) + for (StringRef BuiltinName : NBA->builtinNames()) + AddBuiltinName(BuiltinName); + + // Add current attributes. + if (AL.getNumArgs() == 0) + AddBuiltinName(kWildcard); + else + for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) { + StringRef BuiltinName; + SourceLocation LiteralLoc; + if (!S.checkStringLiteralArgumentAttr(AL, I, BuiltinName, &LiteralLoc)) + return; + + if (Builtin::Context::isBuiltinFunc(BuiltinName.data())) + AddBuiltinName(BuiltinName); + else + S.Diag(LiteralLoc, diag::warn_attribute_no_builtin_invalid_builtin_name) + << BuiltinName << AL.getAttrName()->getName(); + } + + // Repeating the same attribute is fine. + llvm::sort(Names); + Names.erase(std::unique(Names.begin(), Names.end()), Names.end()); + + // Empty no_builtin must be on its own. + if (HasWildcard && Names.size() > 1) + S.Diag(D->getLocation(), + diag::err_attribute_no_builtin_wildcard_or_builtin_name) + << AL.getAttrName()->getName(); + + if (D->hasAttr()) + D->dropAttr(); + D->addAttr(::new (S.Context) + NoBuiltinAttr(S.Context, AL, Names.data(), Names.size())); +} + static void handlePassObjectSizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (D->hasAttr()) { S.Diag(D->getBeginLoc(), diag::err_attribute_only_once_per_parameter) << AL; @@ -1107,8 +1152,8 @@ IdentifierLoc *IL = AL.getArgAsIdent(0); if (!ConsumableAttr::ConvertStrToConsumedState(IL->Ident->getName(), DefaultState)) { - S.Diag(IL->Loc, diag::warn_attribute_type_not_supported) << AL - << IL->Ident; + S.Diag(IL->Loc, diag::warn_attribute_type_not_supported) + << AL << IL->Ident; return; } } else { @@ -1126,8 +1171,8 @@ if (const CXXRecordDecl *RD = ThisType->getAsCXXRecordDecl()) { if (!RD->hasAttr()) { - S.Diag(AL.getLoc(), diag::warn_attr_on_unconsumable_class) << - RD->getNameAsString(); + S.Diag(AL.getLoc(), diag::warn_attr_on_unconsumable_class) + << RD->getNameAsString(); return false; } @@ -1193,10 +1238,10 @@ // FIXME: This check is currently being done in the analysis. It can be // enabled here only after the parser propagates attributes at // template specialization definition, not declaration. - //QualType ReturnType = cast(D)->getType(); - //const CXXRecordDecl *RD = ReturnType->getAsCXXRecordDecl(); + // QualType ReturnType = cast(D)->getType(); + // const CXXRecordDecl *RD = ReturnType->getAsCXXRecordDecl(); // - //if (!RD || !RD->hasAttr()) { + // if (!RD || !RD->hasAttr()) { // S.Diag(AL.getLoc(), diag::warn_return_state_for_unconsumable_type) << // ReturnType.getAsString(); // return; @@ -1212,8 +1257,8 @@ IdentifierLoc *IL = AL.getArgAsIdent(0); if (!ReturnTypestateAttr::ConvertStrToConsumedState(IL->Ident->getName(), ReturnState)) { - S.Diag(IL->Loc, diag::warn_attribute_type_not_supported) << AL - << IL->Ident; + S.Diag(IL->Loc, diag::warn_attribute_type_not_supported) + << AL << IL->Ident; return; } } else { @@ -1225,9 +1270,9 @@ // FIXME: This check is currently being done in the analysis. It can be // enabled here only after the parser propagates attributes at // template specialization definition, not declaration. - //QualType ReturnType; + // QualType ReturnType; // - //if (const ParmVarDecl *Param = dyn_cast(D)) { + // if (const ParmVarDecl *Param = dyn_cast(D)) { // ReturnType = Param->getType(); // //} else if (const CXXConstructorDecl *Constructor = @@ -1239,9 +1284,9 @@ // ReturnType = cast(D)->getCallResultType(); //} // - //const CXXRecordDecl *RD = ReturnType->getAsCXXRecordDecl(); + // const CXXRecordDecl *RD = ReturnType->getAsCXXRecordDecl(); // - //if (!RD || !RD->hasAttr()) { + // if (!RD || !RD->hasAttr()) { // S.Diag(Attr.getLoc(), diag::warn_return_state_for_unconsumable_type) << // ReturnType.getAsString(); // return; @@ -1259,8 +1304,8 @@ IdentifierLoc *Ident = AL.getArgAsIdent(0); StringRef Param = Ident->Ident->getName(); if (!SetTypestateAttr::ConvertStrToConsumedState(Param, NewState)) { - S.Diag(Ident->Loc, diag::warn_attribute_type_not_supported) << AL - << Param; + S.Diag(Ident->Loc, diag::warn_attribute_type_not_supported) + << AL << Param; return; } } else { @@ -1281,8 +1326,8 @@ IdentifierLoc *Ident = AL.getArgAsIdent(0); StringRef Param = Ident->Ident->getName(); if (!TestTypestateAttr::ConvertStrToConsumedState(Param, TestState)) { - S.Diag(Ident->Loc, diag::warn_attribute_type_not_supported) << AL - << Param; + S.Diag(Ident->Loc, diag::warn_attribute_type_not_supported) + << AL << Param; return; } } else { @@ -1303,10 +1348,10 @@ if (auto *TD = dyn_cast(D)) TD->addAttr(::new (S.Context) PackedAttr(S.Context, AL)); else if (auto *FD = dyn_cast(D)) { - bool BitfieldByteAligned = (!FD->getType()->isDependentType() && - !FD->getType()->isIncompleteType() && - FD->isBitField() && - S.Context.getTypeAlign(FD->getType()) <= 8); + bool BitfieldByteAligned = + (!FD->getType()->isDependentType() && + !FD->getType()->isIncompleteType() && FD->isBitField() && + S.Context.getTypeAlign(FD->getType()) <= 8); if (S.getASTContext().getTargetInfo().getTriple().isPS4()) { if (BitfieldByteAligned) @@ -1337,15 +1382,13 @@ << AL << VD->getType() << 0; return false; } - } - else if (const auto *PD = dyn_cast(D)) { + } else if (const auto *PD = dyn_cast(D)) { if (!PD->getType()->getAs()) { S.Diag(AL.getLoc(), diag::warn_iboutlet_object_type) << AL << PD->getType() << 1; return false; } - } - else { + } else { S.Diag(AL.getLoc(), diag::warn_attribute_iboutlet) << AL; return false; } @@ -1394,9 +1437,10 @@ // attributes. So, __attribute__((iboutletcollection(char))) will be // treated as __attribute__((iboutletcollection())). if (!QT->isObjCIdType() && !QT->isObjCObjectType()) { - S.Diag(AL.getLoc(), - QT->isBuiltinType() ? diag::err_iboutletcollection_builtintype - : diag::err_iboutletcollection_type) << QT; + S.Diag(AL.getLoc(), QT->isBuiltinType() + ? diag::err_iboutletcollection_builtintype + : diag::err_iboutletcollection_type) + << QT; return; } @@ -1493,7 +1537,7 @@ handleNonNullAttr(S, D, AL); } else { S.Diag(AL.getLoc(), diag::warn_attribute_nonnull_parm_no_args) - << D->getSourceRange(); + << D->getSourceRange(); } return; } @@ -1560,18 +1604,17 @@ if (!E->isIntegerConstantExpr(I, Context)) { if (OE) Diag(AttrLoc, diag::err_attribute_argument_n_type) - << &TmpAttr << 1 << AANT_ArgumentIntegerConstant - << E->getSourceRange(); + << &TmpAttr << 1 << AANT_ArgumentIntegerConstant + << E->getSourceRange(); else Diag(AttrLoc, diag::err_attribute_argument_type) - << &TmpAttr << AANT_ArgumentIntegerConstant - << E->getSourceRange(); + << &TmpAttr << AANT_ArgumentIntegerConstant << E->getSourceRange(); return; } if (!I.isPowerOf2()) { Diag(AttrLoc, diag::err_alignment_not_power_of_two) - << E->getSourceRange(); + << E->getSourceRange(); return; } } @@ -1581,8 +1624,8 @@ llvm::APSInt I(64); if (!OE->isIntegerConstantExpr(I, Context)) { Diag(AttrLoc, diag::err_attribute_argument_n_type) - << &TmpAttr << 2 << AANT_ArgumentIntegerConstant - << OE->getSourceRange(); + << &TmpAttr << 2 << AANT_ArgumentIntegerConstant + << OE->getSourceRange(); return; } } @@ -1685,21 +1728,21 @@ // Is the function argument a pointer type? QualType T = getFunctionOrMethodParamType(D, Idx.getASTIndex()); - int Err = -1; // No error + int Err = -1; // No error switch (K) { - case OwnershipAttr::Takes: - case OwnershipAttr::Holds: - if (!T->isAnyPointerType() && !T->isBlockPointerType()) - Err = 0; - break; - case OwnershipAttr::Returns: - if (!T->isIntegerType()) - Err = 1; - break; + case OwnershipAttr::Takes: + case OwnershipAttr::Holds: + if (!T->isAnyPointerType() && !T->isBlockPointerType()) + Err = 0; + break; + case OwnershipAttr::Returns: + if (!T->isIntegerType()) + Err = 1; + break; } if (-1 != Err) { - S.Diag(AL.getLoc(), diag::err_ownership_type) << AL << Err - << Ex->getSourceRange(); + S.Diag(AL.getLoc(), diag::err_ownership_type) + << AL << Err << Ex->getSourceRange(); return; } @@ -1707,8 +1750,8 @@ for (const auto *I : D->specific_attrs()) { // Cannot have two ownership attributes of different kinds for the same // index. - if (I->getOwnKind() != K && I->args_end() != - std::find(I->args_begin(), I->args_end(), Idx)) { + if (I->getOwnKind() != K && + I->args_end() != std::find(I->args_begin(), I->args_end(), Idx)) { S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) << AL << I; return; } else if (K == OwnershipAttr::Returns && @@ -1857,8 +1900,8 @@ return; // Check that the value. - if (Model != "global-dynamic" && Model != "local-dynamic" - && Model != "initial-exec" && Model != "local-exec") { + if (Model != "global-dynamic" && Model != "local-dynamic" && + Model != "initial-exec" && Model != "local-exec") { S.Diag(LiteralLoc, diag::err_attr_tlsmodel_arg); return; } @@ -1957,7 +2000,8 @@ } static void handleNoReturnAttr(Sema &S, Decl *D, const ParsedAttr &Attrs) { - if (hasDeclarator(D)) return; + if (hasDeclarator(D)) + return; if (!isa(D)) { S.Diag(Attrs.getLoc(), diag::warn_attribute_wrong_decl_type) @@ -2075,8 +2119,7 @@ // [[carries_dependency]] can only be applied to a parameter if it is a // parameter of a function declaration or lambda. if (!(Scope->getFlags() & clang::Scope::FunctionDeclarationScope)) { - S.Diag(AL.getLoc(), - diag::err_carries_dependency_param_not_function_decl); + S.Diag(AL.getLoc(), diag::err_carries_dependency_param_not_function_decl); return; } } @@ -2139,8 +2182,8 @@ VersionTuple Introduced, VersionTuple Deprecated, VersionTuple Obsoleted) { - StringRef PlatformName - = AvailabilityAttr::getPrettyPlatformName(Platform->getName()); + StringRef PlatformName = + AvailabilityAttr::getPrettyPlatformName(Platform->getName()); if (PlatformName.empty()) PlatformName = Platform->getName(); @@ -2149,24 +2192,22 @@ if (!Introduced.empty() && !Deprecated.empty() && !(Introduced <= Deprecated)) { S.Diag(Range.getBegin(), diag::warn_availability_version_ordering) - << 1 << PlatformName << Deprecated.getAsString() - << 0 << Introduced.getAsString(); + << 1 << PlatformName << Deprecated.getAsString() << 0 + << Introduced.getAsString(); return true; } - if (!Introduced.empty() && !Obsoleted.empty() && - !(Introduced <= Obsoleted)) { + if (!Introduced.empty() && !Obsoleted.empty() && !(Introduced <= Obsoleted)) { S.Diag(Range.getBegin(), diag::warn_availability_version_ordering) - << 2 << PlatformName << Obsoleted.getAsString() - << 0 << Introduced.getAsString(); + << 2 << PlatformName << Obsoleted.getAsString() << 0 + << Introduced.getAsString(); return true; } - if (!Deprecated.empty() && !Obsoleted.empty() && - !(Deprecated <= Obsoleted)) { + if (!Deprecated.empty() && !Obsoleted.empty() && !(Deprecated <= Obsoleted)) { S.Diag(Range.getBegin(), diag::warn_availability_version_ordering) - << 2 << PlatformName << Obsoleted.getAsString() - << 1 << Deprecated.getAsString(); + << 2 << PlatformName << Obsoleted.getAsString() << 1 + << Deprecated.getAsString(); return true; } @@ -2263,7 +2304,8 @@ Which = 0; FirstVersion = OldIntroduced; SecondVersion = Introduced; - } else if (!versionsMatch(Deprecated, OldDeprecated, OverrideOrImpl)) { + } else if (!versionsMatch(Deprecated, OldDeprecated, + OverrideOrImpl)) { Which = 1; FirstVersion = Deprecated; SecondVersion = OldDeprecated; @@ -2276,15 +2318,15 @@ if (Which == -1) { Diag(OldAA->getLocation(), diag::warn_mismatched_availability_override_unavail) - << AvailabilityAttr::getPrettyPlatformName(Platform->getName()) - << (AMK == AMK_Override); + << 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() - << (AMK == AMK_Override); + << Which + << AvailabilityAttr::getPrettyPlatformName(Platform->getName()) + << FirstVersion.getAsString() << SecondVersion.getAsString() + << (AMK == AMK_Override); } if (AMK == AMK_Override) Diag(CI.getLoc(), diag::note_overridden_method); @@ -2326,10 +2368,8 @@ } } - if (FoundAny && - MergedIntroduced == Introduced && - MergedDeprecated == Deprecated && - MergedObsoleted == Obsoleted) + if (FoundAny && MergedIntroduced == Introduced && + MergedDeprecated == Deprecated && MergedObsoleted == Obsoleted) return nullptr; // Only create a new attribute if !OverrideOrImpl, but we want to do @@ -2354,7 +2394,7 @@ IdentifierInfo *II = Platform->Ident; if (AvailabilityAttr::getPrettyPlatformName(II->getName()).empty()) S.Diag(Platform->Loc, diag::warn_availability_unknown_platform) - << Platform->Ident; + << Platform->Ident; auto *ND = dyn_cast(D); if (!ND) // We warned about this already, so just return. @@ -2401,37 +2441,37 @@ 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(NewMajor); + 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(NewMajor); + } - return VersionTuple(2, 0); - }; + return VersionTuple(2, 0); + }; - auto NewIntroduced = adjustWatchOSVersion(Introduced.Version); - auto NewDeprecated = adjustWatchOSVersion(Deprecated.Version); - auto NewObsoleted = adjustWatchOSVersion(Obsoleted.Version); - - AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr( - ND, AL, NewII, true /*Implicit*/, NewIntroduced, NewDeprecated, - NewObsoleted, IsUnavailable, Str, IsStrict, Replacement, - Sema::AMK_None, - PriorityModifier + Sema::AP_InferredFromOtherPlatform); - if (NewAttr) - D->addAttr(NewAttr); - } + auto NewIntroduced = adjustWatchOSVersion(Introduced.Version); + auto NewDeprecated = adjustWatchOSVersion(Deprecated.Version); + auto NewObsoleted = adjustWatchOSVersion(Obsoleted.Version); + + AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr( + ND, AL, NewII, true /*Implicit*/, NewIntroduced, NewDeprecated, + NewObsoleted, IsUnavailable, Str, IsStrict, Replacement, + Sema::AMK_None, + PriorityModifier + Sema::AP_InferredFromOtherPlatform); + 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. @@ -2449,7 +2489,7 @@ PriorityModifier + Sema::AP_InferredFromOtherPlatform); if (NewAttr) D->addAttr(NewAttr); - } + } } } @@ -2508,10 +2548,8 @@ } // 'type_visibility' can only go on a type or namespace. - if (isTypeVisibility && - !(isa(D) || - isa(D) || - isa(D))) { + if (isTypeVisibility && !(isa(D) || isa(D) || + isa(D))) { S.Diag(AL.getRange().getBegin(), diag::err_attribute_wrong_decl_type) << AL << ExpectedTypeOrNamespace; return; @@ -2525,8 +2563,8 @@ VisibilityAttr::VisibilityType type; if (!VisibilityAttr::ConvertStrToVisibilityType(TypeStr, type)) { - S.Diag(LiteralLoc, diag::warn_attribute_type_not_supported) << AL - << TypeStr; + S.Diag(LiteralLoc, diag::warn_attribute_type_not_supported) + << AL << TypeStr; return; } @@ -2582,15 +2620,13 @@ S.Diag(TD->getLocation(), diag::err_nsobject_attribute); return; } - } - else if (const auto *PD = dyn_cast(D)) { + } else if (const auto *PD = dyn_cast(D)) { QualType T = PD->getType(); if (!T->isCARCBridgableType()) { S.Diag(PD->getLocation(), diag::err_nsobject_attribute); return; } - } - else { + } else { // It is okay to include this attribute on properties, e.g.: // // @property (retain, nonatomic) struct Bork *Q __attribute__((NSObject)); @@ -2647,7 +2683,7 @@ if (Idx.isSigned() && Idx.isNegative()) { S.Diag(AL.getLoc(), diag::err_attribute_sentinel_less_than_zero) - << E->getSourceRange(); + << E->getSourceRange(); return; } @@ -2670,7 +2706,7 @@ // FIXME: This error message could be improved, it would be nice // to say what the bounds actually are. S.Diag(AL.getLoc(), diag::err_attribute_sentinel_not_zero_or_one) - << E->getSourceRange(); + << E->getSourceRange(); return; } } @@ -2700,8 +2736,10 @@ QualType Ty = V->getType(); if (Ty->isBlockPointerType() || Ty->isFunctionPointerType()) { const FunctionType *FT = Ty->isFunctionPointerType() - ? D->getFunctionType() - : Ty->castAs()->getPointeeType()->getAs(); + ? D->getFunctionType() + : Ty->castAs() + ->getPointeeType() + ->getAs(); if (!cast(FT)->isVariadic()) { int m = Ty->isFunctionPointerType() ? 0 : 1; S.Diag(AL.getLoc(), diag::warn_attribute_sentinel_not_variadic) << m; @@ -2764,7 +2802,7 @@ if (!D->canBeWeakImported(isDef)) { if (isDef) S.Diag(AL.getLoc(), diag::warn_attribute_invalid_on_definition) - << "weak_import"; + << "weak_import"; else if (isa(D) || isa(D) || (S.Context.getTargetInfo().getTriple().isOSDarwin() && (isa(D) || isa(D)))) { @@ -2796,9 +2834,9 @@ } WorkGroupAttr *Existing = D->getAttr(); - if (Existing && !(Existing->getXDim() == WGSize[0] && - Existing->getYDim() == WGSize[1] && - Existing->getZDim() == WGSize[2])) + if (Existing && + !(Existing->getXDim() == WGSize[0] && Existing->getYDim() == WGSize[1] && + Existing->getZDim() == WGSize[2])) S.Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL; D->addAttr(::new (S.Context) @@ -2866,7 +2904,7 @@ if (ExistingAttr->getName() == Name) return nullptr; Diag(ExistingAttr->getLocation(), diag::warn_mismatched_section) - << 1 /*section*/; + << 1 /*section*/; Diag(CI.getLoc(), diag::note_previous_attribute); return nullptr; } @@ -2876,8 +2914,8 @@ bool Sema::checkSectionName(SourceLocation LiteralLoc, StringRef SecName) { std::string Error = Context.getTargetInfo().isValidSectionSpecifier(SecName); if (!Error.empty()) { - Diag(LiteralLoc, diag::err_attribute_section_invalid_for_target) << Error - << 1 /*'section'*/; + Diag(LiteralLoc, diag::err_attribute_section_invalid_for_target) + << Error << 1 /*'section'*/; return false; } return true; @@ -2897,8 +2935,7 @@ // If the target wants to validate the section specifier, make it happen. std::string Error = S.Context.getTargetInfo().isValidSectionSpecifier(Str); if (!Error.empty()) { - S.Diag(LiteralLoc, diag::err_attribute_section_invalid_for_target) - << Error; + S.Diag(LiteralLoc, diag::err_attribute_section_invalid_for_target) << Error; return; } @@ -2934,7 +2971,7 @@ if (ExistingAttr->getName() == Name) return nullptr; Diag(ExistingAttr->getLocation(), diag::warn_mismatched_section) - << 0 /*codeseg*/; + << 0 /*codeseg*/; Diag(CI.getLoc(), diag::note_previous_attribute); return nullptr; } @@ -2950,10 +2987,9 @@ return; if (const auto *ExistingAttr = D->getAttr()) { if (!ExistingAttr->isImplicit()) { - S.Diag(AL.getLoc(), - ExistingAttr->getName() == Str - ? diag::warn_duplicate_codeseg_attribute - : diag::err_conflicting_codeseg_attribute); + S.Diag(AL.getLoc(), ExistingAttr->getName() == Str + ? diag::warn_duplicate_codeseg_attribute + : diag::err_conflicting_codeseg_attribute); return; } D->dropAttr(); @@ -3035,8 +3071,8 @@ FD = dyn_cast(DRE->getDecl()); NI = DRE->getNameInfo(); if (!FD) { - S.Diag(Loc, diag::err_attribute_cleanup_arg_not_function) << 1 - << NI.getName(); + S.Diag(Loc, diag::err_attribute_cleanup_arg_not_function) + << 1 << NI.getName(); return; } } else if (auto *ULE = dyn_cast(E)) { @@ -3045,8 +3081,8 @@ FD = S.ResolveSingleFunctionTemplateSpecialization(ULE, true); NI = ULE->getNameInfo(); if (!FD) { - S.Diag(Loc, diag::err_attribute_cleanup_arg_not_function) << 2 - << NI.getName(); + S.Diag(Loc, diag::err_attribute_cleanup_arg_not_function) + << 2 << NI.getName(); if (ULE->getType() == S.Context.OverloadTy) S.NoteAllOverloadCandidates(ULE); return; @@ -3058,7 +3094,7 @@ if (FD->getNumParams() != 1) { S.Diag(Loc, diag::err_attribute_cleanup_func_must_take_one_arg) - << NI.getName(); + << NI.getName(); return; } @@ -3066,10 +3102,10 @@ // If this ever proves to be a problem it should be easy to fix. QualType Ty = S.Context.getPointerType(cast(D)->getType()); QualType ParamTy = FD->getParamDecl(0)->getType(); - if (S.CheckAssignmentConstraints(FD->getParamDecl(0)->getLocation(), - ParamTy, Ty) != Sema::Compatible) { + if (S.CheckAssignmentConstraints(FD->getParamDecl(0)->getLocation(), ParamTy, + Ty) != Sema::Compatible) { S.Diag(Loc, diag::err_attribute_cleanup_func_arg_incompatible_type) - << NI.getName() << ParamTy << Ty; + << NI.getName() << ParamTy << Ty; return; } @@ -3108,8 +3144,7 @@ QualType Ty = getFunctionOrMethodParamType(D, Idx.getASTIndex()); bool NotNSStringTy = !isNSStringType(Ty, S.Context); - if (NotNSStringTy && - !isCFStringType(Ty, S.Context) && + if (NotNSStringTy && !isCFStringType(Ty, S.Context) && (!Ty->isPointerType() || !Ty->castAs()->getPointeeType()->isCharType())) { S.Diag(AL.getLoc(), diag::err_format_attribute_not) @@ -3118,8 +3153,7 @@ return; } Ty = getFunctionOrMethodResultType(D); - if (!isNSStringType(Ty, S.Context) && - !isCFStringType(Ty, S.Context) && + if (!isNSStringType(Ty, S.Context) && !isCFStringType(Ty, S.Context) && (!Ty->isPointerType() || !Ty->castAs()->getPointeeType()->isCharType())) { S.Diag(AL.getLoc(), diag::err_format_attribute_result_not) @@ -3204,8 +3238,7 @@ int FirstArg) { // Check whether we already have an equivalent format attribute. for (auto *F : D->specific_attrs()) { - if (F->getType() == Format && - F->getFormatIdx() == FormatIdx && + if (F->getType() == Format && F->getFormatIdx() == FormatIdx && F->getFirstArg() == FirstArg) { // If we don't have a valid location for this attribute, adopt the // location. @@ -3271,7 +3304,7 @@ if (ArgIdx == 0) { S.Diag(AL.getLoc(), diag::err_format_attribute_implicit_this_format_string) - << IdxExpr->getSourceRange(); + << IdxExpr->getSourceRange(); return; } ArgIdx--; @@ -3283,8 +3316,8 @@ if (Kind == CFStringFormat) { if (!isCFStringType(Ty, S.Context)) { S.Diag(AL.getLoc(), diag::err_format_attribute_not) - << "a CFString" << IdxExpr->getSourceRange() - << getFunctionOrMethodParamRange(D, ArgIdx); + << "a CFString" << IdxExpr->getSourceRange() + << getFunctionOrMethodParamRange(D, ArgIdx); return; } } else if (Kind == NSStringFormat) { @@ -3292,15 +3325,15 @@ // semantics? if (!isNSStringType(Ty, S.Context)) { S.Diag(AL.getLoc(), diag::err_format_attribute_not) - << "an NSString" << IdxExpr->getSourceRange() - << getFunctionOrMethodParamRange(D, ArgIdx); + << "an NSString" << IdxExpr->getSourceRange() + << getFunctionOrMethodParamRange(D, ArgIdx); return; } } else if (!Ty->isPointerType() || !Ty->castAs()->getPointeeType()->isCharType()) { S.Diag(AL.getLoc(), diag::err_format_attribute_not) - << "a string type" << IdxExpr->getSourceRange() - << getFunctionOrMethodParamRange(D, ArgIdx); + << "a string type" << IdxExpr->getSourceRange() + << getFunctionOrMethodParamRange(D, ArgIdx); return; } @@ -3325,10 +3358,10 @@ if (Kind == StrftimeFormat) { if (FirstArg != 0) { S.Diag(AL.getLoc(), diag::err_format_strftime_third_parameter) - << FirstArgExpr->getSourceRange(); + << FirstArgExpr->getSourceRange(); return; } - // if 0 it disables parameter checking (to use with e.g. va_list) + // if 0 it disables parameter checking (to use with e.g. va_list) } else if (FirstArg != 0 && FirstArg != NumArgs) { S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds) << AL << 3 << FirstArgExpr->getSourceRange(); @@ -3489,8 +3522,8 @@ RD = dyn_cast(D); if (!RD || !RD->isUnion()) { - S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) << AL - << ExpectedUnion; + S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) + << AL << ExpectedUnion; return; } @@ -3502,7 +3535,7 @@ } RecordDecl::field_iterator Field = RD->field_begin(), - FieldEnd = RD->field_end(); + FieldEnd = RD->field_end(); if (Field == FieldEnd) { S.Diag(AL.getLoc(), diag::warn_transparent_union_attribute_zero_fields); return; @@ -3513,7 +3546,7 @@ if (FirstType->hasFloatingRepresentation() || FirstType->isVectorType()) { S.Diag(FirstField->getLocation(), diag::warn_transparent_union_attribute_floating) - << FirstType->isVectorType() << FirstType; + << FirstType->isVectorType() << FirstType; return; } @@ -3534,15 +3567,15 @@ S.Context.getTypeAlign(FieldType) > FirstAlign) { // Warn if we drop the attribute. bool isSize = S.Context.getTypeSize(FieldType) != FirstSize; - unsigned FieldBits = isSize? S.Context.getTypeSize(FieldType) - : S.Context.getTypeAlign(FieldType); + unsigned FieldBits = isSize ? S.Context.getTypeSize(FieldType) + : S.Context.getTypeAlign(FieldType); S.Diag(Field->getLocation(), - diag::warn_transparent_union_attribute_field_size_align) - << isSize << Field->getDeclName() << FieldBits; - unsigned FirstBits = isSize? FirstSize : FirstAlign; + diag::warn_transparent_union_attribute_field_size_align) + << isSize << Field->getDeclName() << FieldBits; + unsigned FirstBits = isSize ? FirstSize : FirstAlign; S.Diag(FirstField->getLocation(), diag::note_transparent_union_first_field_size_align) - << isSize << FirstBits; + << isSize << FirstBits; return; } } @@ -3585,22 +3618,21 @@ if (!T->isDependentType() && !T->isAnyPointerType() && !T->isReferenceType() && !T->isMemberPointerType()) { Diag(AttrLoc, diag::warn_attribute_pointer_or_reference_only) - << &TmpAttr /*TmpAttr.getName()*/ << T << D->getSourceRange(); + << &TmpAttr /*TmpAttr.getName()*/ << T << D->getSourceRange(); return; } if (!E->isValueDependent()) { llvm::APSInt Alignment; - ExprResult ICE - = VerifyIntegerConstantExpression(E, &Alignment, - diag::err_align_value_attribute_argument_not_int, - /*AllowFold*/ false); + ExprResult ICE = VerifyIntegerConstantExpression( + E, &Alignment, diag::err_align_value_attribute_argument_not_int, + /*AllowFold*/ false); if (ICE.isInvalid()) return; if (!Alignment.isPowerOf2()) { Diag(AttrLoc, diag::err_alignment_not_power_of_two) - << E->getSourceRange(); + << E->getSourceRange(); return; } @@ -3667,14 +3699,15 @@ if (FD->isBitField()) DiagKind = 3; } else if (!isa(D)) { - Diag(AttrLoc, diag::err_attribute_wrong_decl_type) << &TmpAttr - << (TmpAttr.isC11() ? ExpectedVariableOrField - : ExpectedVariableFieldOrTag); + Diag(AttrLoc, diag::err_attribute_wrong_decl_type) + << &TmpAttr + << (TmpAttr.isC11() ? ExpectedVariableOrField + : ExpectedVariableFieldOrTag); return; } if (DiagKind != -1) { Diag(AttrLoc, diag::err_alignas_attribute_wrong_decl_type) - << &TmpAttr << DiagKind; + << &TmpAttr << DiagKind; return; } } @@ -3700,10 +3733,9 @@ // FIXME: Cache the number on the AL object? llvm::APSInt Alignment; - ExprResult ICE - = VerifyIntegerConstantExpression(E, &Alignment, - diag::err_aligned_attribute_argument_not_int, - /*AllowFold*/ false); + ExprResult ICE = VerifyIntegerConstantExpression( + E, &Alignment, diag::err_aligned_attribute_argument_not_int, + /*AllowFold*/ false); if (ICE.isInvalid()) return; @@ -3717,7 +3749,7 @@ if (!(TmpAttr.isAlignas() && !Alignment)) { if (!llvm::isPowerOf2_64(AlignVal)) { Diag(AttrLoc, diag::err_alignment_not_power_of_two) - << E->getSourceRange(); + << E->getSourceRange(); return; } } @@ -3727,8 +3759,8 @@ Context.getTargetInfo().getTriple().isOSBinFormatCOFF() ? 8192 : 268435456; if (AlignVal > MaxValidAlignment) { - Diag(AttrLoc, diag::err_attribute_aligned_too_great) << MaxValidAlignment - << E->getSourceRange(); + Diag(AttrLoc, diag::err_attribute_aligned_too_great) + << MaxValidAlignment << E->getSourceRange(); return; } @@ -3792,7 +3824,7 @@ CharUnits NaturalAlign = Context.getTypeAlignInChars(UnderlyingTy); if (NaturalAlign > RequestedAlign) Diag(AlignasAttr->getLocation(), diag::err_alignas_underaligned) - << DiagTy << (unsigned)NaturalAlign.getQuantity(); + << DiagTy << (unsigned)NaturalAlign.getQuantity(); } } @@ -4081,8 +4113,9 @@ // ImplicitParm or VarTemplateSpecialization). if (VD->getKind() != Decl::Var) { Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) - << AL << (getLangOpts().CPlusPlus ? ExpectedFunctionVariableOrClass - : ExpectedVariableOrFunction); + << AL + << (getLangOpts().CPlusPlus ? ExpectedFunctionVariableOrClass + : ExpectedVariableOrFunction); return nullptr; } // Attribute does not apply to non-static local variables. @@ -4104,8 +4137,9 @@ // ImplicitParm or VarTemplateSpecialization). if (VD->getKind() != Decl::Var) { Diag(AL.getLocation(), diag::warn_attribute_wrong_decl_type) - << &AL << (getLangOpts().CPlusPlus ? ExpectedFunctionVariableOrClass - : ExpectedVariableOrFunction); + << &AL + << (getLangOpts().CPlusPlus ? ExpectedFunctionVariableOrClass + : ExpectedVariableOrFunction); return nullptr; } // Attribute does not apply to non-static local variables. @@ -4262,12 +4296,13 @@ } static void handleCallConvAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - if (hasDeclarator(D)) return; + if (hasDeclarator(D)) + return; // Diagnostic is emitted elsewhere: here we store the (valid) AL // in the Decl node for syntactic reasoning, e.g., pretty-printing. CallingConv CC; - if (S.CheckCallingConvAttr(AL, CC, /*FD*/nullptr)) + if (S.CheckCallingConvAttr(AL, CC, /*FD*/ nullptr)) return; if (!isa(D)) { @@ -4428,7 +4463,7 @@ return true; if (Attrs.hasProcessingCache()) { - CC = (CallingConv) Attrs.getProcessingCache(); + CC = (CallingConv)Attrs.getProcessingCache(); return false; } @@ -4468,12 +4503,11 @@ CC = CC_X86RegCall; break; case ParsedAttr::AT_MSABI: - CC = Context.getTargetInfo().getTriple().isOSWindows() ? CC_C : - CC_Win64; + CC = Context.getTargetInfo().getTriple().isOSWindows() ? CC_C : CC_Win64; break; case ParsedAttr::AT_SysVABI: - CC = Context.getTargetInfo().getTriple().isOSWindows() ? CC_X86_64SysV : - CC_C; + CC = Context.getTargetInfo().getTriple().isOSWindows() ? CC_X86_64SysV + : CC_C; break; case ParsedAttr::AT_Pcs: { StringRef StrRef; @@ -4502,7 +4536,8 @@ case ParsedAttr::AT_PreserveAll: CC = CC_PreserveAll; break; - default: llvm_unreachable("unexpected attribute kind"); + default: + llvm_unreachable("unexpected attribute kind"); } TargetInfo::CallingConvCheckResult A = TargetInfo::CCCR_OK; @@ -4573,7 +4608,7 @@ } } - Attrs.setProcessingCache((unsigned) CC); + Attrs.setProcessingCache((unsigned)CC); return false; } @@ -4675,7 +4710,7 @@ if (Context.getTargetInfo().getRegParmMax() == 0) { Diag(AL.getLoc(), diag::err_attribute_regparm_wrong_platform) - << NumParamsExpr->getSourceRange(); + << NumParamsExpr->getSourceRange(); AL.setInvalid(); return true; } @@ -4683,7 +4718,8 @@ numParams = NP; if (numParams > Context.getTargetInfo().getRegParmMax()) { Diag(AL.getLoc(), diag::err_attribute_regparm_invalid_number) - << Context.getTargetInfo().getRegParmMax() << NumParamsExpr->getSourceRange(); + << Context.getTargetInfo().getRegParmMax() + << NumParamsExpr->getSourceRange(); AL.setInvalid(); return true; } @@ -4714,8 +4750,8 @@ } // Make sure we can fit it in 32 bits. if (!I.isIntN(32)) { - S.Diag(E->getExprLoc(), diag::err_ice_too_large) << I.toString(10, false) - << 32 << /* Unsigned */ 1; + S.Diag(E->getExprLoc(), diag::err_ice_too_large) + << I.toString(10, false) << 32 << /* Unsigned */ 1; return nullptr; } if (I < 0) @@ -4949,8 +4985,8 @@ // Attributes on parameters are used for out-parameters, // passed as pointers-to-pointers. unsigned DiagID = K == Sema::RetainOwnershipKind::CF - ? /*pointer-to-CF-pointer*/2 - : /*pointer-to-OSObject-pointer*/3; + ? /*pointer-to-CF-pointer*/ 2 + : /*pointer-to-OSObject-pointer*/ 3; ReturnType = Param->getType()->getPointeeType(); if (ReturnType.isNull()) { S.Diag(D->getBeginLoc(), diag::warn_ns_attribute_wrong_parameter_type) @@ -4962,7 +4998,8 @@ } else { AttributeDeclKind ExpectedDeclKind; switch (AL.getKind()) { - default: llvm_unreachable("invalid ownership attribute"); + default: + llvm_unreachable("invalid ownership attribute"); case ParsedAttr::AT_NSReturnsRetained: case ParsedAttr::AT_NSReturnsAutoreleased: case ParsedAttr::AT_NSReturnsNotRetained: @@ -4985,7 +5022,8 @@ bool Cf; unsigned ParmDiagID = 2; // Pointer-to-CF-pointer switch (AL.getKind()) { - default: llvm_unreachable("invalid ownership attribute"); + default: + llvm_unreachable("invalid ownership attribute"); case ParsedAttr::AT_NSReturnsRetained: TypeOK = isValidSubjectOfNSReturnsRetainedAttribute(ReturnType); Cf = false; @@ -5020,11 +5058,7 @@ << AL << ParmDiagID << AL.getRange(); } else { // Needs to be kept in sync with warn_ns_attribute_wrong_return_type. - enum : unsigned { - Function, - Method, - Property - } SubjectKind = Function; + enum : unsigned { Function, Method, Property } SubjectKind = Function; if (isa(D)) SubjectKind = Method; else if (isa(D)) @@ -5036,29 +5070,29 @@ } switch (AL.getKind()) { - default: - llvm_unreachable("invalid ownership attribute"); - case ParsedAttr::AT_NSReturnsAutoreleased: - handleSimpleAttribute(S, D, AL); - return; - case ParsedAttr::AT_CFReturnsNotRetained: - handleSimpleAttribute(S, D, AL); - return; - case ParsedAttr::AT_NSReturnsNotRetained: - handleSimpleAttribute(S, D, AL); - return; - case ParsedAttr::AT_CFReturnsRetained: - handleSimpleAttribute(S, D, AL); - return; - case ParsedAttr::AT_NSReturnsRetained: - handleSimpleAttribute(S, D, AL); - return; - case ParsedAttr::AT_OSReturnsRetained: - handleSimpleAttribute(S, D, AL); - return; - case ParsedAttr::AT_OSReturnsNotRetained: - handleSimpleAttribute(S, D, AL); - return; + default: + llvm_unreachable("invalid ownership attribute"); + case ParsedAttr::AT_NSReturnsAutoreleased: + handleSimpleAttribute(S, D, AL); + return; + case ParsedAttr::AT_CFReturnsNotRetained: + handleSimpleAttribute(S, D, AL); + return; + case ParsedAttr::AT_NSReturnsNotRetained: + handleSimpleAttribute(S, D, AL); + return; + case ParsedAttr::AT_CFReturnsRetained: + handleSimpleAttribute(S, D, AL); + return; + case ParsedAttr::AT_NSReturnsRetained: + handleSimpleAttribute(S, D, AL); + return; + case ParsedAttr::AT_OSReturnsRetained: + handleSimpleAttribute(S, D, AL); + return; + case ParsedAttr::AT_OSReturnsNotRetained: + handleSimpleAttribute(S, D, AL); + return; }; } @@ -5094,14 +5128,14 @@ const DeclContext *DC = Method->getDeclContext(); if (const auto *PDecl = dyn_cast_or_null(DC)) { - S.Diag(D->getBeginLoc(), diag::warn_objc_requires_super_protocol) << Attrs - << 0; + S.Diag(D->getBeginLoc(), diag::warn_objc_requires_super_protocol) + << Attrs << 0; S.Diag(PDecl->getLocation(), diag::note_protocol_decl); return; } if (Method->getMethodFamily() == OMF_dealloc) { - S.Diag(D->getBeginLoc(), diag::warn_objc_requires_super_protocol) << Attrs - << 1; + S.Diag(D->getBeginLoc(), diag::warn_objc_requires_super_protocol) + << Attrs << 1; return; } @@ -5156,9 +5190,9 @@ return; } IdentifierInfo *ClassMethod = - AL.getArgAsIdent(1) ? AL.getArgAsIdent(1)->Ident : nullptr; + AL.getArgAsIdent(1) ? AL.getArgAsIdent(1)->Ident : nullptr; IdentifierInfo *InstanceMethod = - AL.getArgAsIdent(2) ? AL.getArgAsIdent(2)->Ident : nullptr; + AL.getArgAsIdent(2) ? AL.getArgAsIdent(2)->Ident : nullptr; D->addAttr(::new (S.Context) ObjCBridgeRelatedAttr( S.Context, AL, RelatedClass, ClassMethod, InstanceMethod)); } @@ -5224,7 +5258,8 @@ } static void handleObjCOwnershipAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - if (hasDeclarator(D)) return; + if (hasDeclarator(D)) + return; S.Diag(D->getBeginLoc(), diag::err_attribute_wrong_decl_type) << AL.getRange() << AL << ExpectedVariable; @@ -5235,10 +5270,8 @@ const auto *VD = cast(D); QualType QT = VD->getType(); - if (!QT->isDependentType() && - !QT->isObjCLifetimeType()) { - S.Diag(AL.getLoc(), diag::err_objc_precise_lifetime_bad_type) - << QT; + if (!QT->isDependentType() && !QT->isObjCLifetimeType()) { + S.Diag(AL.getLoc(), diag::err_objc_precise_lifetime_bad_type) << QT; return; } @@ -5415,8 +5448,8 @@ ARMInterruptAttr::InterruptType Kind; if (!ARMInterruptAttr::ConvertStrToInterruptType(Str, Kind)) { - S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) << AL << Str - << ArgLoc; + S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) + << AL << Str << ArgLoc; return; } @@ -5620,7 +5653,8 @@ handleSimpleAttribute(S, D, AL); } -static void handleWebAssemblyImportModuleAttr(Sema &S, Decl *D, const ParsedAttr &AL) { +static void handleWebAssemblyImportModuleAttr(Sema &S, Decl *D, + const ParsedAttr &AL) { if (!isFunctionOrMethod(D)) { S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) << "'import_module'" << ExpectedFunction; @@ -5642,7 +5676,8 @@ WebAssemblyImportModuleAttr(S.Context, AL, Str)); } -static void handleWebAssemblyImportNameAttr(Sema &S, Decl *D, const ParsedAttr &AL) { +static void handleWebAssemblyImportNameAttr(Sema &S, Decl *D, + const ParsedAttr &AL) { if (!isFunctionOrMethod(D)) { S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) << "'import_name'" << ExpectedFunction; @@ -5663,12 +5698,11 @@ FD->addAttr(::new (S.Context) WebAssemblyImportNameAttr(S.Context, AL, Str)); } -static void handleRISCVInterruptAttr(Sema &S, Decl *D, - const ParsedAttr &AL) { +static void handleRISCVInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // Warn about repeated attributes. if (const auto *A = D->getAttr()) { S.Diag(AL.getRange().getBegin(), - diag::warn_riscv_repeated_interrupt_attribute); + diag::warn_riscv_repeated_interrupt_attribute); S.Diag(A->getLocation(), diag::note_riscv_repeated_interrupt_attribute); return; } @@ -5695,26 +5729,26 @@ if (D->getFunctionType() == nullptr) { S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) - << "'interrupt'" << ExpectedFunction; + << "'interrupt'" << ExpectedFunction; return; } if (hasFunctionProto(D) && getFunctionOrMethodNumParams(D) != 0) { S.Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid) - << /*RISC-V*/ 2 << 0; + << /*RISC-V*/ 2 << 0; return; } if (!getFunctionOrMethodResultType(D)->isVoidType()) { S.Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid) - << /*RISC-V*/ 2 << 1; + << /*RISC-V*/ 2 << 1; return; } RISCVInterruptAttr::InterruptType Kind; if (!RISCVInterruptAttr::ConvertStrToInterruptType(Str, Kind)) { - S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) << AL << Str - << ArgLoc; + S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) + << AL << Str << ArgLoc; return; } @@ -5883,7 +5917,7 @@ // Also don't warn on function pointer typedefs. const auto *TD = dyn_cast(D); if (TD && (TD->getUnderlyingType()->isFunctionPointerType() || - TD->getUnderlyingType()->isFunctionType())) + TD->getUnderlyingType()->isFunctionType())) return; // Attribute can only be applied to function types. if (!isa(D)) { @@ -6033,7 +6067,7 @@ } static void handleAssertCapabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - SmallVector Args; + SmallVector Args; if (!checkLockFunAttrCommon(S, D, AL, Args)) return; @@ -6043,7 +6077,7 @@ static void handleAcquireCapabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - SmallVector Args; + SmallVector Args; if (!checkLockFunAttrCommon(S, D, AL, Args)) return; @@ -6053,7 +6087,7 @@ static void handleTryAcquireCapabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - SmallVector Args; + SmallVector Args; if (!checkTryLockFunAttrCommon(S, D, AL, Args)) return; @@ -6077,7 +6111,7 @@ return; // check that all arguments are lockable objects - SmallVector Args; + SmallVector Args; checkAttrArgsAreCapabilityObjs(S, D, AL, Args); if (Args.empty()) return; @@ -6191,8 +6225,8 @@ S.Diag(AL.getLoc(), diag::err_attribute_requires_opencl_version) << AL << "2.0" << 0; else - S.Diag(AL.getLoc(), diag::warn_opencl_attr_deprecated_ignored) << AL - << "2.0"; + S.Diag(AL.getLoc(), diag::warn_opencl_attr_deprecated_ignored) + << AL << "2.0"; } /// Handles semantic checking for features that are common to all attributes, @@ -6256,11 +6290,10 @@ } } - // OpenCL v2.0 s6.6 - read_write can be used for image types to specify that an - // image object can be read and written. - // OpenCL v2.0 s6.13.6 - A kernel cannot read from and write to the same pipe - // object. Using the read_write (or __read_write) qualifier with the pipe - // qualifier is a compilation error. + // OpenCL v2.0 s6.6 - read_write can be used for image types to specify that + // an image object can be read and written. OpenCL v2.0 s6.13.6 - A kernel + // cannot read from and write to the same pipe object. Using the read_write + // (or __read_write) qualifier with the pipe qualifier is a compilation error. if (const auto *PDecl = dyn_cast(D)) { const Type *DeclTy = PDecl->getType().getCanonicalType().getTypePtr(); if (AL.getAttrName()->getName().find("read_write") != StringRef::npos) { @@ -6286,9 +6319,11 @@ } if (A.getKind() == ParsedAttr::AT_AlwaysDestroy) - handleSimpleAttributeWithExclusions(S, D, A); + handleSimpleAttributeWithExclusions(S, D, + A); else - handleSimpleAttributeWithExclusions(S, D, A); + handleSimpleAttributeWithExclusions(S, D, + A); } static void handleUninitializedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -6578,6 +6613,9 @@ case ParsedAttr::AT_DiagnoseIf: handleDiagnoseIfAttr(S, D, AL); break; + case ParsedAttr::AT_NoBuiltin: + handleNoBuiltinAttr(S, D, AL); + break; case ParsedAttr::AT_ExtVectorType: handleExtVectorTypeAttr(S, D, AL); break; @@ -7277,8 +7315,8 @@ S.Diag(AL.getLoc(), diag::warn_unknown_attribute_ignored) << AL << AL.getRange(); } else { - S.Diag(AL.getLoc(), diag::warn_attribute_not_on_decl) << AL - << AL.getRange(); + S.Diag(AL.getLoc(), diag::warn_attribute_not_on_decl) + << AL << AL.getRange(); } } } @@ -7295,8 +7333,8 @@ /// DeclClonePragmaWeak - clone existing decl (maybe definition), /// \#pragma weak needs a non-definition decl and source may not have one. -NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II, - SourceLocation Loc) { +NamedDecl *Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II, + SourceLocation Loc) { assert(isa(ND) || isa(ND)); NamedDecl *NewD = nullptr; if (auto *FD = dyn_cast(ND)) { @@ -7318,7 +7356,7 @@ // a typedef. QualType FDTy = FD->getType(); if (const auto *FT = FDTy->getAs()) { - SmallVector Params; + SmallVector Params; for (const auto &AI : FT->param_types()) { ParmVarDecl *Param = BuildParmVarDeclForTypedef(NewFD, Loc, AI); Param->setScopeInfo(0, Params.size()); @@ -7340,7 +7378,8 @@ /// DeclApplyPragmaWeak - A declaration (maybe definition) needs \#pragma weak /// applied to it, possibly with an alias. void Sema::DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, WeakInfo &W) { - if (W.getUsed()) return; // only do this once + if (W.getUsed()) + return; // only do this once W.setUsed(true); if (W.getAlias()) { // clone decl, impersonate __attribute(weak,alias(...)) IdentifierInfo *NDId = ND->getIdentifier(); @@ -7421,8 +7460,7 @@ // 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. - if (!isa(D) && !isa(D) && - !isa(D)) + if (!isa(D) && !isa(D) && !isa(D)) return false; // Silently accept unsupported uses of __weak in both user and system @@ -7550,8 +7588,8 @@ // For +new, infer availability from -init. if (const auto *MD = dyn_cast(D)) { if (S.NSAPIObj && ClassReceiver) { - ObjCMethodDecl *Init = ClassReceiver->lookupInstanceMethod( - S.NSAPIObj->getInitSelector()); + ObjCMethodDecl *Init = + ClassReceiver->lookupInstanceMethod(S.NSAPIObj->getInitSelector()); if (Init && Result == AR_Available && MD->isClassMethod() && MD->getSelector() == S.NSAPIObj->getNewSelector() && MD->definedInNSObject(S.getASTContext())) { @@ -7564,7 +7602,6 @@ return {Result, D}; } - /// whether we should emit a diagnostic for \c K and \c DeclVersion in /// the context of \c Ctx. For example, we should emit an unavailable diagnostic /// in a deprecated context, but not the other way around. @@ -7759,14 +7796,11 @@ /// may not be the same as ReferringDecl, i.e. if an EnumDecl is annotated and /// we refer to a member EnumConstantDecl, ReferringDecl is the EnumConstantDecl /// and OffendingDecl is the EnumDecl. -static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, - Decl *Ctx, const NamedDecl *ReferringDecl, - const NamedDecl *OffendingDecl, - StringRef Message, - ArrayRef Locs, - const ObjCInterfaceDecl *UnknownObjCClass, - const ObjCPropertyDecl *ObjCProperty, - bool ObjCPropertyAccess) { +static void DoEmitAvailabilityWarning( + Sema &S, AvailabilityResult K, Decl *Ctx, const NamedDecl *ReferringDecl, + const NamedDecl *OffendingDecl, StringRef Message, + ArrayRef Locs, const ObjCInterfaceDecl *UnknownObjCClass, + const ObjCPropertyDecl *ObjCProperty, bool ObjCPropertyAccess) { // Diagnostics for deprecated or unavailable. unsigned diag, diag_message, diag_fwdclass_message; unsigned diag_available_here = diag::note_availability_specified_here; @@ -7898,7 +7932,8 @@ }; switch (AL->getImplicitReason()) { - case UnavailableAttr::IR_None: break; + case UnavailableAttr::IR_None: + break; case UnavailableAttr::IR_ARCForbiddenType: flagARCError(); @@ -7945,8 +7980,7 @@ CharSourceRange UseRange; if (!Replacement.empty()) - UseRange = - CharSourceRange::getCharRange(Loc, S.getLocForEndOfToken(Loc)); + UseRange = CharSourceRange::getCharRange(Loc, S.getLocForEndOfToken(Loc)); if (UseRange.isValid()) { if (const auto *MethodDecl = dyn_cast(ReferringDecl)) { Selector Sel = MethodDecl->getSelector(); @@ -7988,7 +8022,7 @@ } S.Diag(NoteLocation, diag_available_here) - << OffendingDecl << available_here_select_kind; + << OffendingDecl << available_here_select_kind; } static void handleDelayedAvailabilityCheck(Sema &S, DelayedDiagnostic &DD, @@ -8012,7 +8046,8 @@ // When delaying diagnostics to run in the context of a parsed // declaration, we only want to actually emit anything if parsing // succeeds. - if (!decl) return; + if (!decl) + return; // We emit all the active diagnostics in this pool or any of its // parents. In general, we'll get one pool for the decl spec @@ -8024,10 +8059,11 @@ const DelayedDiagnosticPool *pool = &poppedPool; do { bool AnyAccessFailures = false; - for (DelayedDiagnosticPool::pool_iterator - i = pool->pool_begin(), e = pool->pool_end(); i != e; ++i) { + for (DelayedDiagnosticPool::pool_iterator i = pool->pool_begin(), + e = pool->pool_end(); + i != e; ++i) { // This const_cast is a bit lame. Really, Triggered should be mutable. - DelayedDiagnostic &diag = const_cast(*i); + DelayedDiagnostic &diag = const_cast(*i); if (diag.Triggered) continue; @@ -8067,26 +8103,22 @@ curPool->steal(pool); } -static void EmitAvailabilityWarning(Sema &S, AvailabilityResult AR, - const NamedDecl *ReferringDecl, - const NamedDecl *OffendingDecl, - StringRef Message, - ArrayRef Locs, - const ObjCInterfaceDecl *UnknownObjCClass, - const ObjCPropertyDecl *ObjCProperty, - bool ObjCPropertyAccess) { +static void EmitAvailabilityWarning( + Sema &S, AvailabilityResult AR, const NamedDecl *ReferringDecl, + const NamedDecl *OffendingDecl, StringRef Message, + ArrayRef Locs, const ObjCInterfaceDecl *UnknownObjCClass, + const ObjCPropertyDecl *ObjCProperty, bool ObjCPropertyAccess) { // Delay if we're currently parsing a declaration. if (S.DelayedDiagnostics.shouldDelayDiagnostics()) { - S.DelayedDiagnostics.add( - DelayedDiagnostic::makeAvailability( - AR, Locs, ReferringDecl, OffendingDecl, UnknownObjCClass, - ObjCProperty, Message, ObjCPropertyAccess)); + S.DelayedDiagnostics.add(DelayedDiagnostic::makeAvailability( + AR, Locs, ReferringDecl, OffendingDecl, UnknownObjCClass, ObjCProperty, + Message, ObjCPropertyAccess)); return; } Decl *Ctx = cast(S.getCurLexicalContext()); - DoEmitAvailabilityWarning(S, AR, Ctx, ReferringDecl, OffendingDecl, - Message, Locs, UnknownObjCClass, ObjCProperty, + DoEmitAvailabilityWarning(S, AR, Ctx, ReferringDecl, OffendingDecl, Message, + Locs, UnknownObjCClass, ObjCProperty, ObjCPropertyAccess); } @@ -8210,7 +8242,8 @@ bool VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *PRE) { if (PRE->isClassReceiver()) - DiagnoseDeclAvailability(PRE->getClassReceiver(), PRE->getReceiverLocation()); + DiagnoseDeclAvailability(PRE->getClassReceiver(), + PRE->getReceiverLocation()); return true; } @@ -8261,7 +8294,7 @@ return; const AvailabilityAttr *AA = - getAttrForPlatform(SemaRef.getASTContext(), OffendingDecl); + getAttrForPlatform(SemaRef.getASTContext(), OffendingDecl); VersionTuple Introduced = AA->getIntroduced(); if (AvailabilityStack.back() >= Introduced) @@ -8345,8 +8378,9 @@ const char *ExtraIndentation = " "; std::string FixItString; llvm::raw_string_ostream FixItOS(FixItString); - FixItOS << "if (" << (SemaRef.getLangOpts().ObjC ? "@available" - : "__builtin_available") + FixItOS << "if (" + << (SemaRef.getLangOpts().ObjC ? "@available" + : "__builtin_available") << "(" << AvailabilityAttr::getPlatformNameSourceSpelling( SemaRef.getASTContext().getTargetInfo().getPlatformName()) @@ -8443,7 +8477,7 @@ ObjCInterfaceDecl *ClassReceiver) { std::string Message; AvailabilityResult Result; - const NamedDecl* OffendingDecl; + const NamedDecl *OffendingDecl; // See if this declaration is unavailable, deprecated, or partial. std::tie(Result, OffendingDecl) = ShouldDiagnoseAvailabilityOfDecl(*this, D, &Message, ClassReceiver); diff --git a/clang/test/CodeGen/no-builtin.cpp b/clang/test/CodeGen/no-builtin.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/no-builtin.cpp @@ -0,0 +1,54 @@ +// RUN: %clang_cc1 -triple x86_64-linux-gnu -S -emit-llvm -o - %s | FileCheck %s + +// CHECK-LABEL: define void @foo_no_mempcy() #0 +extern "C" void foo_no_mempcy() __attribute__((no_builtin("memcpy"))) {} + +// CHECK-LABEL: define void @foo_no_mempcy_twice() #0 +extern "C" void foo_no_mempcy_twice() __attribute__((no_builtin("memcpy"))) __attribute__((no_builtin("memcpy"))) {} + +// CHECK-LABEL: define void @foo_no_builtins() #1 +extern "C" void foo_no_builtins() __attribute__((no_builtin)) {} + +// CHECK-LABEL: define void @foo_no_mempcy_memset() #2 +extern "C" void foo_no_mempcy_memset() __attribute__((no_builtin("memset", "memcpy"))) {} + +// CHECK-LABEL: define void @separate_attrs() #2 +extern "C" void separate_attrs() __attribute__((no_builtin("memset"))) __attribute__((no_builtin("memcpy"))) {} + +// CHECK-LABEL: define void @separate_attrs_ordering() #2 +extern "C" void separate_attrs_ordering() __attribute__((no_builtin("memcpy"))) __attribute__((no_builtin("memset"))) {} + +struct A { + virtual int foo() const __attribute__((no_builtin("memcpy"))) { return 1; } + virtual ~A(); +}; + +struct B : public A { + int foo() const override __attribute__((no_builtin("memmove"))) { return 2; } + virtual ~B(); +}; + +// CHECK-LABEL: define void @call_a_foo(%struct.A* %a) #3 +extern "C" void call_a_foo(A *a) { + // CHECK: %call = call i32 %2(%struct.A* %0) #6 + a->foo(); +} + +// CHECK-LABEL: define void @call_b_foo(%struct.B* %b) #3 +extern "C" void call_b_foo(B *b) { + // CHECK: %call = call i32 %2(%struct.B* %0) #7 + b->foo(); +} + +A::~A() {} // Anchoring A so A::foo() gets generated +B::~B() {} // Anchoring B so B::foo() gets generated + +// CHECK-LABEL: define linkonce_odr i32 @_ZNK1A3fooEv(%struct.A* %this) unnamed_addr #0 comdat align 2 +// CHECK-LABEL: define linkonce_odr i32 @_ZNK1B3fooEv(%struct.B* %this) unnamed_addr #5 comdat align 2 + +// CHECK: attributes #0 = {{{.*}}"no-builtin-memcpy"{{.*}}} +// CHECK: attributes #1 = {{{.*}}"no-builtins"{{.*}}} +// CHECK: attributes #2 = {{{.*}}"no-builtin-memcpy"{{.*}}"no-builtin-memset"{{.*}}} +// CHECK: attributes #5 = {{{.*}}"no-builtin-memmove"{{.*}}} +// CHECK: attributes #6 = { "no-builtin-memcpy" } +// CHECK: attributes #7 = { "no-builtin-memmove" } diff --git a/clang/test/Misc/pragma-attribute-supported-attributes-list.test b/clang/test/Misc/pragma-attribute-supported-attributes-list.test --- a/clang/test/Misc/pragma-attribute-supported-attributes-list.test +++ b/clang/test/Misc/pragma-attribute-supported-attributes-list.test @@ -74,6 +74,7 @@ // CHECK-NEXT: NSConsumed (SubjectMatchRule_variable_is_parameter) // CHECK-NEXT: NSConsumesSelf (SubjectMatchRule_objc_method) // CHECK-NEXT: Naked (SubjectMatchRule_function) +// CHECK-NEXT: NoBuiltin (SubjectMatchRule_function) // CHECK-NEXT: NoCommon (SubjectMatchRule_variable) // CHECK-NEXT: NoDebug (SubjectMatchRule_type_alias, SubjectMatchRule_hasType_functionType, SubjectMatchRule_objc_method, SubjectMatchRule_variable_not_is_parameter) // CHECK-NEXT: NoDestroy (SubjectMatchRule_variable) diff --git a/clang/test/Sema/no-builtin.cpp b/clang/test/Sema/no-builtin.cpp new file mode 100644 --- /dev/null +++ b/clang/test/Sema/no-builtin.cpp @@ -0,0 +1,48 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fsyntax-only -verify %s + +/// Prevent use of all builtins. +void valid_attribute_all_1() __attribute__((no_builtin)) {} +void valid_attribute_all_2() __attribute__((no_builtin())) {} + +/// Prevent use of specific builtins. +void valid_attribute_function() __attribute__((no_builtin("memcpy"))) {} +void valid_attribute_functions() __attribute__((no_builtin("memcpy"))) __attribute__((no_builtin("memcmp"))) {} + +/// Many times the same builtin is fine. +void many_attribute_function_1() __attribute__((no_builtin)) __attribute__((no_builtin)) {} +void many_attribute_function_2() __attribute__((no_builtin("memcpy"))) __attribute__((no_builtin("memcpy"))) {} +void many_attribute_function_3() __attribute__((no_builtin("memcpy", "memcpy"))) {} +void many_attribute_function_4() __attribute__((no_builtin("memcpy", "memcpy"))) __attribute__((no_builtin("memcpy"))) {} + +/// Invalid builtin name. +void invalid_builtin() __attribute__((no_builtin("not_a_builtin"))) {} +// expected-warning@-1 {{'not_a_builtin' is not a valid builtin name for no_builtin}} + +/// Can't use bare no_builtin with a named one. +void wildcard_and_functionname() __attribute__((no_builtin)) __attribute__((no_builtin("memcpy"))) {} +// expected-error@-1 {{empty no_builtin cannot be composed with named ones}} + +/// Can't attach attribute to a variable. +int __attribute__((no_builtin)) variable; +// expected-warning@-1 {{'no_builtin' attribute only applies to functions}} + +/// Can't attach attribute to a declaration. +void nobuiltin_on_declaration() __attribute__((no_builtin)); +// expected-error@-1 {{no_builtin attribute is permitted on definitions only}} + +struct S { + /// Can't attach attribute to a defaulted function, + S() + __attribute__((no_builtin)) = default; + // expected-error@-1 {{no_builtin attribute has no effect on defaulted or deleted functions}} + + /// Can't attach attribute to a deleted function, + S(const S &) + __attribute__((no_builtin)) = delete; + // expected-error@-1 {{no_builtin attribute has no effect on defaulted or deleted functions}} +}; + +/// Can't attach attribute to an aliased function. +void alised_function() {} +void aliasing_function() __attribute__((no_builtin)) __attribute__((alias("alised_function"))); +// expected-error@-1 {{no_builtin attribute is permitted on definitions only}} \ No newline at end of file