diff options
Diffstat (limited to 'clang')
133 files changed, 2467 insertions, 712 deletions
diff --git a/clang/docs/CommandGuide/clang.rst b/clang/docs/CommandGuide/clang.rst index 7d49f2c..4c1f8e4 100644 --- a/clang/docs/CommandGuide/clang.rst +++ b/clang/docs/CommandGuide/clang.rst @@ -645,7 +645,7 @@ Driver Options Save internal code generation (LLVM) statistics to a file in the current directory (:option:`-save-stats`/"-save-stats=cwd") or the directory - of the output file ("-save-state=obj"). + of the output file ("-save-stats=obj"). You can also use environment variables to control the statistics reporting. Setting ``CC_PRINT_INTERNAL_STAT`` to ``1`` enables the feature, the report diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst index 34e1bf1..29ef20f 100644 --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -68,6 +68,9 @@ It can be used like this: ``__has_builtin`` should not be used to detect support for a builtin macro; use ``#ifdef`` instead. + When compiling with target offloading, ``__has_builtin`` only considers the + currently active target. + ``__has_constexpr_builtin`` --------------------------- diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index ec51ffd..4a5e184 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -37,6 +37,8 @@ Potentially Breaking Changes C/C++ Language Potentially Breaking Changes ------------------------------------------- +- The ``__has_builtin`` function now only considers the currently active target when being used with target offloading. + C++ Specific Potentially Breaking Changes ----------------------------------------- - For C++20 modules, the Reduced BMI mode will be the default option. This may introduce @@ -89,9 +91,18 @@ Non-comprehensive list of changes in this release ------------------------------------------------- - Added ``__builtin_elementwise_minnumnum`` and ``__builtin_elementwise_maxnumnum``. +- Trapping UBSan (e.g. ``-fsanitize-trap=undefined``) now emits a string describing the reason for + trapping into the generated debug info. This feature allows debuggers (e.g. LLDB) to display + the reason for trapping if the trap is reached. The string is currently encoded in the debug + info as an artificial frame that claims to be inlined at the trap location. The function used + for the artificial frame is an artificial function whose name encodes the reason for trapping. + The encoding used is currently the same as ``__builtin_verbose_trap`` but might change in the future. + This feature is enabled by default but can be disabled by compiling with + ``-fno-sanitize-annotate-debug-info-traps``. New Compiler Flags ------------------ +- New option ``-fno-sanitize-annotate-debug-info-traps`` added to disable emitting trap reasons into the debug info when compiling with trapping UBSan (e.g. ``-fsanitize-trap=undefined``). Deprecated Compiler Flags ------------------------- @@ -130,6 +141,9 @@ Bug Fixes to Compiler Builtins Bug Fixes to Attribute Support ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +- ``[[nodiscard]]`` is now respected on Objective-C and Objective-C++ methods. + (#GH141504) + Bug Fixes to C++ Support ^^^^^^^^^^^^^^^^^^^^^^^^ - Diagnose binding a reference to ``*nullptr`` during constant evaluation. (#GH48665) diff --git a/clang/docs/analyzer/checkers/unix_malloc_example.c b/clang/docs/analyzer/checkers/unix_malloc_example.c index 68c5a4a..30df074 100644 --- a/clang/docs/analyzer/checkers/unix_malloc_example.c +++ b/clang/docs/analyzer/checkers/unix_malloc_example.c @@ -2,7 +2,7 @@ void test() { int *p = malloc(1); free(p); - free(p); // warn: attempt to free released memory + free(p); // warn: attempt to release already released memory } void test() { diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 523c032..708c6e2 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -16,6 +16,7 @@ #include "clang/AST/APNumericStorage.h" #include "clang/AST/APValue.h" #include "clang/AST/ASTVector.h" +#include "clang/AST/Attr.h" #include "clang/AST/ComputeDependence.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclAccessPair.h" @@ -262,6 +263,12 @@ public: SourceRange &R1, SourceRange &R2, ASTContext &Ctx) const; + /// Returns the WarnUnusedResultAttr that is declared on the callee + /// or its return type declaration, together with a NamedDecl that + /// refers to the declaration the attribute is attached to. + static std::pair<const NamedDecl *, const WarnUnusedResultAttr *> + getUnusedResultAttrImpl(const Decl *Callee, QualType ReturnType); + /// isLValue - True if this expression is an "l-value" according to /// the rules of the current language. C and C++ give somewhat /// different rules for this concept, but in general, the result of @@ -3190,11 +3197,13 @@ public: /// type. QualType getCallReturnType(const ASTContext &Ctx) const; - /// Returns the WarnUnusedResultAttr that is either declared on the called - /// function, or its return type declaration, together with a NamedDecl that - /// refers to the declaration the attribute is attached onto. - std::pair<const NamedDecl *, const Attr *> - getUnusedResultAttr(const ASTContext &Ctx) const; + /// Returns the WarnUnusedResultAttr that is declared on the callee + /// or its return type declaration, together with a NamedDecl that + /// refers to the declaration the attribute is attached to. + std::pair<const NamedDecl *, const WarnUnusedResultAttr *> + getUnusedResultAttr(const ASTContext &Ctx) const { + return getUnusedResultAttrImpl(getCalleeDecl(), getCallReturnType(Ctx)); + } /// Returns true if this call expression should warn on unused results. bool hasUnusedResultAttr(const ASTContext &Ctx) const { diff --git a/clang/include/clang/AST/ExprObjC.h b/clang/include/clang/AST/ExprObjC.h index 8210be3..b923230 100644 --- a/clang/include/clang/AST/ExprObjC.h +++ b/clang/include/clang/AST/ExprObjC.h @@ -13,6 +13,7 @@ #ifndef LLVM_CLANG_AST_EXPROBJC_H #define LLVM_CLANG_AST_EXPROBJC_H +#include "clang/AST/Attr.h" #include "clang/AST/ComputeDependence.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" @@ -1234,6 +1235,19 @@ public: /// of `instancetype` (in that case it's an expression type). QualType getCallReturnType(ASTContext &Ctx) const; + /// Returns the WarnUnusedResultAttr that is declared on the callee + /// or its return type declaration, together with a NamedDecl that + /// refers to the declaration the attribute is attached to. + std::pair<const NamedDecl *, const WarnUnusedResultAttr *> + getUnusedResultAttr(ASTContext &Ctx) const { + return getUnusedResultAttrImpl(getMethodDecl(), getCallReturnType(Ctx)); + } + + /// Returns true if this message send should warn on unused results. + bool hasUnusedResultAttr(ASTContext &Ctx) const { + return getUnusedResultAttr(Ctx).second != nullptr; + } + /// Source range of the receiver. SourceRange getReceiverRange() const; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index fefdaba..76747d2 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -9417,9 +9417,9 @@ def NonStringDocs : Documentation { let Category = DocCatDecl; let Content = [{ The ``nonstring`` attribute can be applied to the declaration of a variable or -a field whose type is a character array to specify that the character array is -not intended to behave like a null-terminated string. This will silence -diagnostics with code like: +a field whose type is a character pointer or character array to specify that +the buffer is not intended to behave like a null-terminated string. This will +silence diagnostics with code like: .. code-block:: c diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def index e137738..423b696 100644 --- a/clang/include/clang/Basic/CodeGenOptions.def +++ b/clang/include/clang/Basic/CodeGenOptions.def @@ -307,6 +307,7 @@ CODEGENOPT(SanitizeBinaryMetadataAtomics, 1, 0, Benign) ///< Emit PCs for atomic CODEGENOPT(SanitizeBinaryMetadataUAR, 1, 0, Benign) ///< Emit PCs for start of functions ///< that are subject for use-after-return checking. CODEGENOPT(SanitizeStats , 1, 0, Benign) ///< Collect statistics for sanitizers. +CODEGENOPT(SanitizeDebugTrapReasons, 1, 1 , Benign) ///< Enable UBSan trapping messages CODEGENOPT(SimplifyLibCalls , 1, 1, Benign) ///< Set when -fbuiltin is enabled. CODEGENOPT(SoftFloat , 1, 0, Benign) ///< -soft-float. CODEGENOPT(SpeculativeLoadHardening, 1, 0, Benign) ///< Enable speculative load hardening. diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 81cbd38..da4216d 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -12391,6 +12391,13 @@ def err_invalid_module_name : Error<"%0 is an invalid name for a module">; def err_extern_def_in_header_unit : Error< "non-inline external definitions are not permitted in C++ header units">; +def warn_exposure : Warning < + "TU local entity %0 is exposed">, + InGroup<DiagGroup<"TU-local-entity-exposure">>; +def warn_reference_tu_local_entity_in_other_tu : Warning < + "instantiation of %0 triggers reference to TU-local entity %1 from other TU '%2'">, + InGroup<DiagGroup<"reference-tu-local-entity-in-other-tu">>; + def warn_experimental_header_unit : Warning< "the implementation of header units is in an experimental phase">, InGroup<DiagGroup<"experimental-header-units">>; diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td index 29d8aea..9961544 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td @@ -147,6 +147,18 @@ def UndefAttr : CIR_TypedAttr<"Undef", "undef"> { } //===----------------------------------------------------------------------===// +// PoisonAttr +//===----------------------------------------------------------------------===// + +def CIR_PoisonAttr : CIR_TypedAttr<"Poison", "poison"> { + let summary = "Represent a typed poison constant"; + let description = [{ + The PoisonAttr represents a typed poison constant, corresponding to LLVM's + notion of poison. + }]; +} + +//===----------------------------------------------------------------------===// // IntegerAttr //===----------------------------------------------------------------------===// diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h index d17c85f..e1a5c3d 100644 --- a/clang/include/clang/CIR/MissingFeatures.h +++ b/clang/include/clang/CIR/MissingFeatures.h @@ -287,7 +287,6 @@ struct MissingFeatures { // Future CIR attributes static bool optInfoAttr() { return false; } - static bool poisonAttr() { return false; } }; } // namespace cir diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 916400e..eb53821 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -2320,21 +2320,21 @@ def fsymbol_partition_EQ : Joined<["-"], "fsymbol-partition=">, Group<f_Group>, defm atomic_remote_memory : BoolFOption<"atomic-remote-memory", LangOpts<"AtomicRemoteMemory">, DefaultFalse, - PosFlag<SetTrue, [], [ClangOption, CC1Option], "May have">, - NegFlag<SetFalse, [], [ClangOption], "Assume no">, - BothFlags<[], [ClangOption], " atomic operations on remote memory">>; + PosFlag<SetTrue, [], [ClangOption, CC1Option, FlangOption, FC1Option], "May have">, + NegFlag<SetFalse, [], [ClangOption, FlangOption], "Assume no">, + BothFlags<[], [ClangOption, FlangOption], " atomic operations on remote memory">>; defm atomic_fine_grained_memory : BoolFOption<"atomic-fine-grained-memory", LangOpts<"AtomicFineGrainedMemory">, DefaultFalse, - PosFlag<SetTrue, [], [ClangOption, CC1Option], "May have">, - NegFlag<SetFalse, [], [ClangOption], "Assume no">, - BothFlags<[], [ClangOption], " atomic operations on fine-grained memory">>; + PosFlag<SetTrue, [], [ClangOption, CC1Option, FlangOption, FC1Option], "May have">, + NegFlag<SetFalse, [], [ClangOption, FlangOption], "Assume no">, + BothFlags<[], [ClangOption, FlangOption], " atomic operations on fine-grained memory">>; defm atomic_ignore_denormal_mode : BoolFOption<"atomic-ignore-denormal-mode", LangOpts<"AtomicIgnoreDenormalMode">, DefaultFalse, - PosFlag<SetTrue, [], [ClangOption, CC1Option], "Allow">, - NegFlag<SetFalse, [], [ClangOption], "Disallow">, - BothFlags<[], [ClangOption], " atomic operations to ignore denormal mode">>; + PosFlag<SetTrue, [], [ClangOption, CC1Option, FlangOption, FC1Option], "Allow">, + NegFlag<SetFalse, [], [ClangOption, FlangOption], "Disallow">, + BothFlags<[], [ClangOption, FlangOption], " atomic operations to ignore denormal mode">>; defm memory_profile : OptInCC1FFlag<"memory-profile", "Enable", "Disable", " heap memory profiling">; def fmemory_profile_EQ : Joined<["-"], "fmemory-profile=">, @@ -2597,6 +2597,16 @@ def fsanitize_undefined_trap_on_error def fno_sanitize_undefined_trap_on_error : Flag<["-"], "fno-sanitize-undefined-trap-on-error">, Group<f_clang_Group>, Alias<fno_sanitize_trap_EQ>, AliasArgs<["undefined"]>; +defm sanitize_debug_trap_reasons + : BoolFOption< + "sanitize-debug-trap-reasons", + CodeGenOpts<"SanitizeDebugTrapReasons">, DefaultTrue, + PosFlag<SetTrue, [], [ClangOption, CC1Option], + "Annotate trap blocks in debug info with UBSan trap reasons">, + NegFlag<SetFalse, [], [ClangOption, CC1Option], + "Do not annotate trap blocks in debug info with UBSan trap " + "reasons">>; + defm sanitize_minimal_runtime : BoolOption<"f", "sanitize-minimal-runtime", CodeGenOpts<"SanitizeMinimalRuntime">, DefaultFalse, PosFlag<SetTrue>, @@ -5360,9 +5370,9 @@ defm amdgpu_precise_memory_op " precise memory mode (AMDGPU only)">; def munsafe_fp_atomics : Flag<["-"], "munsafe-fp-atomics">, - Visibility<[ClangOption, CC1Option]>, Alias<fatomic_ignore_denormal_mode>; + Visibility<[ClangOption, CC1Option, FlangOption, FC1Option]>, Alias<fatomic_ignore_denormal_mode>; def mno_unsafe_fp_atomics : Flag<["-"], "mno-unsafe-fp-atomics">, - Visibility<[ClangOption]>, Alias<fno_atomic_ignore_denormal_mode>; + Visibility<[ClangOption, FlangOption]>, Alias<fno_atomic_ignore_denormal_mode>; def faltivec : Flag<["-"], "faltivec">, Group<f_Group>; def fno_altivec : Flag<["-"], "fno-altivec">, Group<f_Group>; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 73eb730..423dcf9 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -9945,6 +9945,20 @@ private: VisibleModuleSet VisibleModules; + /// Whether we had imported any named modules. + bool HadImportedNamedModules = false; + /// The set of instantiations we need to check if they references TU-local + /// entity from TUs. This only makes sense if we imported any named modules. + llvm::SmallVector<std::pair<FunctionDecl *, SourceLocation>> + PendingCheckReferenceForTULocal; + /// Implement [basic.link]p18, which requires that we can't use TU-local + /// entities from other TUs (ignoring header units). + void checkReferenceToTULocalFromOtherTU(FunctionDecl *FD, + SourceLocation PointOfInstantiation); + /// Implement [basic.link]p17, which diagnose for non TU local exposure in + /// module interface or module partition. + void checkExposure(const TranslationUnitDecl *TU); + ///@} // diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td index 38584c9..6225977 100644 --- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td +++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td @@ -206,21 +206,15 @@ def CallAndMessageChecker : Checker<"CallAndMessage">, Documentation<HasDocumentation>, Dependencies<[CallAndMessageModeling]>; -def DereferenceModeling : Checker<"DereferenceModeling">, - HelpText<"General support for dereference related checkers">, - Documentation<NotDocumented>, - Hidden; - def FixedAddressDereferenceChecker : Checker<"FixedAddressDereference">, HelpText<"Check for dereferences of fixed addresses">, - Documentation<HasDocumentation>, - Dependencies<[DereferenceModeling]>; + Documentation<HasDocumentation>; -def NullDereferenceChecker : Checker<"NullDereference">, - HelpText<"Check for dereferences of null pointers">, - Documentation<HasDocumentation>, - Dependencies<[DereferenceModeling]>; +def NullDereferenceChecker + : Checker<"NullDereference">, + HelpText<"Check for dereferences of null pointers">, + Documentation<HasDocumentation>; def NonNullParamChecker : Checker<"NonNullParamChecker">, HelpText<"Check for null pointers passed as arguments to a function whose " diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index 63ac536..d0ddb2e 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -1022,7 +1022,8 @@ bool Compiler<Emitter>::VisitPointerArithBinOp(const BinaryOperator *E) { if (classifyPrim(E) != PT_Ptr) return this->emitDecayPtr(PT_Ptr, classifyPrim(E), E); return true; - } else if (Op == BO_Sub) { + } + if (Op == BO_Sub) { if (!this->emitSubOffset(OffsetType, E)) return false; @@ -3703,7 +3704,7 @@ bool Compiler<Emitter>::VisitBlockExpr(const BlockExpr *E) { return true; const Function *Func = nullptr; - if (auto F = Ctx.getOrCreateObjCBlock(E)) + if (const Function *F = Ctx.getOrCreateObjCBlock(E)) Func = F; if (!Func) @@ -4288,7 +4289,8 @@ bool Compiler<Emitter>::visitZeroArrayInitializer(QualType T, const Expr *E) { return false; } return true; - } else if (ElemType->isRecordType()) { + } + if (ElemType->isRecordType()) { const Record *R = getRecord(ElemType); for (size_t I = 0; I != NumElems; ++I) { @@ -4302,7 +4304,8 @@ bool Compiler<Emitter>::visitZeroArrayInitializer(QualType T, const Expr *E) { return false; } return true; - } else if (ElemType->isArrayType()) { + } + if (ElemType->isArrayType()) { for (size_t I = 0; I != NumElems; ++I) { if (!this->emitConstUint32(I, E)) return false; @@ -4774,11 +4777,10 @@ VarCreationState Compiler<Emitter>::visitVarDecl(const VarDecl *VD, if (!this->visit(Init)) return false; return this->emitSetLocal(*VarT, Offset, VD) && Scope.destroyLocals(); - } else { + } if (!this->visit(Init)) return false; return this->emitSetLocal(*VarT, Offset, VD); - } } } else { if (std::optional<unsigned> Offset = this->allocateLocal( @@ -4805,7 +4807,7 @@ bool Compiler<Emitter>::visitAPValue(const APValue &Val, PrimType ValType, assert(!DiscardResult); if (Val.isInt()) return this->emitConst(Val.getInt(), ValType, E); - else if (Val.isFloat()) { + if (Val.isFloat()) { APFloat F = Val.getFloat(); return this->emitFloat(F, E); } @@ -4816,9 +4818,8 @@ bool Compiler<Emitter>::visitAPValue(const APValue &Val, PrimType ValType, APValue::LValueBase Base = Val.getLValueBase(); if (const Expr *BaseExpr = Base.dyn_cast<const Expr *>()) return this->visit(BaseExpr); - else if (const auto *VD = Base.dyn_cast<const ValueDecl *>()) { + if (const auto *VD = Base.dyn_cast<const ValueDecl *>()) return this->visitDeclRef(VD, E); - } } else if (Val.isMemberPointer()) { if (const ValueDecl *MemberDecl = Val.getMemberPointerDecl()) return this->emitGetMemberPtr(MemberDecl, E); @@ -4854,7 +4855,8 @@ bool Compiler<Emitter>::visitAPValueInitializer(const APValue &Val, } } return true; - } else if (Val.isUnion()) { + } + if (Val.isUnion()) { const FieldDecl *UnionField = Val.getUnionField(); const Record *R = this->getRecord(UnionField->getParent()); assert(R); @@ -4864,7 +4866,8 @@ bool Compiler<Emitter>::visitAPValueInitializer(const APValue &Val, if (!this->visitAPValue(F, T, E)) return false; return this->emitInitField(T, RF->Offset, E); - } else if (Val.isArray()) { + } + if (Val.isArray()) { const auto *ArrType = T->getAsArrayTypeUnsafe(); QualType ElemType = ArrType->getElementType(); for (unsigned A = 0, AN = Val.getArraySize(); A != AN; ++A) { @@ -4981,12 +4984,10 @@ bool Compiler<Emitter>::VisitCallExpr(const CallExpr *E) { // Calls to replaceable operator new/operator delete. if (FuncDecl->isUsableAsGlobalAllocationFunctionInConstantEvaluation()) { - if (FuncDecl->getDeclName().isAnyOperatorNew()) { + if (FuncDecl->getDeclName().isAnyOperatorNew()) return VisitBuiltinCallExpr(E, Builtin::BI__builtin_operator_new); - } else { - assert(FuncDecl->getDeclName().getCXXOverloadedOperator() == OO_Delete); - return VisitBuiltinCallExpr(E, Builtin::BI__builtin_operator_delete); - } + assert(FuncDecl->getDeclName().getCXXOverloadedOperator() == OO_Delete); + return VisitBuiltinCallExpr(E, Builtin::BI__builtin_operator_delete); } // Explicit calls to trivial destructors @@ -5455,7 +5456,9 @@ bool Compiler<Emitter>::visitReturnStmt(const ReturnStmt *RS) { return false; this->emitCleanup(); return this->emitRet(*ReturnType, RS); - } else if (RE->getType()->isVoidType()) { + } + + if (RE->getType()->isVoidType()) { if (!this->visit(RE)) return false; } else { @@ -5500,7 +5503,7 @@ template <class Emitter> bool Compiler<Emitter>::visitIfStmt(const IfStmt *IS) { if (std::optional<bool> BoolValue = getBoolValue(IS->getCond())) { if (*BoolValue) return visitChildStmt(IS->getThen()); - else if (const Stmt *Else = IS->getElse()) + if (const Stmt *Else = IS->getElse()) return visitChildStmt(Else); return true; } @@ -5992,7 +5995,7 @@ bool Compiler<Emitter>::compileConstructor(const CXXConstructorDecl *Ctor) { if (!this->emitThis(Ctor)) return false; - auto PVD = Ctor->getParamDecl(0); + const ParmVarDecl *PVD = Ctor->getParamDecl(0); ParamOffset PO = this->Params[PVD]; // Must exist. if (!this->emitGetParam(PT_Ptr, PO.Offset, Ctor)) @@ -6153,7 +6156,7 @@ bool Compiler<Emitter>::compileUnionAssignmentOperator( if (!this->emitThis(MD)) return false; - auto PVD = MD->getParamDecl(0); + const ParmVarDecl *PVD = MD->getParamDecl(0); ParamOffset PO = this->Params[PVD]; // Must exist. if (!this->emitGetParam(PT_Ptr, PO.Offset, MD)) diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp index 5463aec..224d65c 100644 --- a/clang/lib/AST/ByteCode/Interp.cpp +++ b/clang/lib/AST/ByteCode/Interp.cpp @@ -845,7 +845,7 @@ bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { return true; } -bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F) { +static bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F) { if (F->isVirtual() && !S.getLangOpts().CPlusPlus20) { const SourceLocation &Loc = S.Current->getLocation(OpPC); diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp index 19d4c0c..3ece7054 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp @@ -240,9 +240,9 @@ static bool interp__builtin_strcmp(InterpState &S, CodePtr OpPC, T CB = PB.deref<T>(); if (CA > CB) return returnResult(1); - else if (CA < CB) + if (CA < CB) return returnResult(-1); - else if (CA.isZero() || CB.isZero()) + if (CA.isZero() || CB.isZero()) return returnResult(0); }); continue; @@ -253,7 +253,7 @@ static bool interp__builtin_strcmp(InterpState &S, CodePtr OpPC, if (CA > CB) return returnResult(1); - else if (CA < CB) + if (CA < CB) return returnResult(-1); if (CA == 0 || CB == 0) return returnResult(0); @@ -1048,7 +1048,7 @@ static bool interp__builtin_atomic_lock_free(InterpState &S, CodePtr OpPC, PtrArg = ICE->getSubExpr(); } - if (auto PtrTy = PtrArg->getType()->getAs<PointerType>()) { + if (const auto *PtrTy = PtrArg->getType()->getAs<PointerType>()) { QualType PointeeType = PtrTy->getPointeeType(); if (!PointeeType->isIncompleteType() && S.getASTContext().getTypeAlignInChars(PointeeType) >= Size) { @@ -1967,7 +1967,8 @@ static bool interp__builtin_memcmp(InterpState &S, CodePtr OpPC, if (A < B) { pushInteger(S, -1, Call->getType()); return true; - } else if (A > B) { + } + if (A > B) { pushInteger(S, 1, Call->getType()); return true; } @@ -1979,7 +1980,8 @@ static bool interp__builtin_memcmp(InterpState &S, CodePtr OpPC, if (A < B) { pushInteger(S, -1, Call->getType()); return true; - } else if (A > B) { + } + if (A > B) { pushInteger(S, 1, Call->getType()); return true; } diff --git a/clang/lib/AST/ByteCode/InterpStack.h b/clang/lib/AST/ByteCode/InterpStack.h index 0b76f1d..580494e 100644 --- a/clang/lib/AST/ByteCode/InterpStack.h +++ b/clang/lib/AST/ByteCode/InterpStack.h @@ -14,11 +14,9 @@ #define LLVM_CLANG_AST_INTERP_INTERPSTACK_H #include "FixedPoint.h" -#include "FunctionPointer.h" #include "IntegralAP.h" #include "MemberPointer.h" #include "PrimType.h" -#include <memory> #include <vector> namespace clang { diff --git a/clang/lib/AST/ByteCode/Pointer.cpp b/clang/lib/AST/ByteCode/Pointer.cpp index 4019b74..9341bc1 100644 --- a/clang/lib/AST/ByteCode/Pointer.cpp +++ b/clang/lib/AST/ByteCode/Pointer.cpp @@ -16,6 +16,7 @@ #include "MemberPointer.h" #include "PrimType.h" #include "Record.h" +#include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/RecordLayout.h" @@ -66,14 +67,14 @@ Pointer::~Pointer() { } } -void Pointer::operator=(const Pointer &P) { +Pointer &Pointer::operator=(const Pointer &P) { // If the current storage type is Block, we need to remove // this pointer from the block. if (isBlockPointer()) { if (P.isBlockPointer() && this->block() == P.block()) { Offset = P.Offset; PointeeStorage.BS.Base = P.PointeeStorage.BS.Base; - return; + return *this; } if (Block *Pointee = PointeeStorage.BS.Pointee) { @@ -101,16 +102,17 @@ void Pointer::operator=(const Pointer &P) { } else { assert(false && "Unhandled storage kind"); } + return *this; } -void Pointer::operator=(Pointer &&P) { +Pointer &Pointer::operator=(Pointer &&P) { // If the current storage type is Block, we need to remove // this pointer from the block. if (isBlockPointer()) { if (P.isBlockPointer() && this->block() == P.block()) { Offset = P.Offset; PointeeStorage.BS.Base = P.PointeeStorage.BS.Base; - return; + return *this; } if (Block *Pointee = PointeeStorage.BS.Pointee) { @@ -138,6 +140,7 @@ void Pointer::operator=(Pointer &&P) { } else { assert(false && "Unhandled storage kind"); } + return *this; } APValue Pointer::toAPValue(const ASTContext &ASTCtx) const { @@ -603,7 +606,7 @@ bool Pointer::pointsToStringLiteral() const { return false; const Expr *E = block()->getDescriptor()->asExpr(); - return E && isa<StringLiteral>(E); + return isa_and_nonnull<StringLiteral>(E); } std::optional<std::pair<Pointer, Pointer>> diff --git a/clang/lib/AST/ByteCode/Pointer.h b/clang/lib/AST/ByteCode/Pointer.h index d17eba5..059f176 100644 --- a/clang/lib/AST/ByteCode/Pointer.h +++ b/clang/lib/AST/ByteCode/Pointer.h @@ -120,8 +120,8 @@ public: Pointer(Block *Pointee, unsigned Base, uint64_t Offset); ~Pointer(); - void operator=(const Pointer &P); - void operator=(Pointer &&P); + Pointer &operator=(const Pointer &P); + Pointer &operator=(Pointer &&P); /// Equality operators are just for tests. bool operator==(const Pointer &P) const { @@ -761,7 +761,7 @@ public: if (Offset < Other.Offset) return ComparisonCategoryResult::Less; - else if (Offset > Other.Offset) + if (Offset > Other.Offset) return ComparisonCategoryResult::Greater; return ComparisonCategoryResult::Equal; diff --git a/clang/lib/AST/ByteCode/Program.cpp b/clang/lib/AST/ByteCode/Program.cpp index 7002724..2421ec4 100644 --- a/clang/lib/AST/ByteCode/Program.cpp +++ b/clang/lib/AST/ByteCode/Program.cpp @@ -418,7 +418,7 @@ Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty, } return allocateDescriptor(D, *T, MDSize, NumElems, IsConst, IsTemporary, IsMutable); - } else { + } // Arrays of composites. In this case, the array is a list of pointers, // followed by the actual elements. const Descriptor *ElemDesc = createDescriptor( @@ -430,7 +430,6 @@ Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty, return {}; return allocateDescriptor(D, Ty, ElemDesc, MDSize, NumElems, IsConst, IsTemporary, IsMutable); - } } // Array of unknown bounds - cannot be accessed and pointer arithmetic @@ -440,14 +439,13 @@ Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty, if (OptPrimType T = Ctx.classify(ElemTy)) { return allocateDescriptor(D, *T, MDSize, IsConst, IsTemporary, Descriptor::UnknownSize{}); - } else { + } const Descriptor *Desc = createDescriptor( D, ElemTy.getTypePtr(), std::nullopt, IsConst, IsTemporary); if (!Desc) return nullptr; return allocateDescriptor(D, Desc, MDSize, IsTemporary, Descriptor::UnknownSize{}); - } } } diff --git a/clang/lib/AST/ByteCode/Program.h b/clang/lib/AST/ByteCode/Program.h index 5d9c422..207ceef 100644 --- a/clang/lib/AST/ByteCode/Program.h +++ b/clang/lib/AST/ByteCode/Program.h @@ -19,10 +19,7 @@ #include "Record.h" #include "Source.h" #include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/PointerUnion.h" -#include "llvm/ADT/StringRef.h" #include "llvm/Support/Allocator.h" -#include <map> #include <vector> namespace clang { diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 2e1a9a3..d85655b 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -1629,20 +1629,20 @@ QualType CallExpr::getCallReturnType(const ASTContext &Ctx) const { return FnType->getReturnType(); } -std::pair<const NamedDecl *, const Attr *> -CallExpr::getUnusedResultAttr(const ASTContext &Ctx) const { +std::pair<const NamedDecl *, const WarnUnusedResultAttr *> +Expr::getUnusedResultAttrImpl(const Decl *Callee, QualType ReturnType) { // If the callee is marked nodiscard, return that attribute - if (const Decl *D = getCalleeDecl()) - if (const auto *A = D->getAttr<WarnUnusedResultAttr>()) + if (Callee != nullptr) + if (const auto *A = Callee->getAttr<WarnUnusedResultAttr>()) return {nullptr, A}; // If the return type is a struct, union, or enum that is marked nodiscard, // then return the return type attribute. - if (const TagDecl *TD = getCallReturnType(Ctx)->getAsTagDecl()) + if (const TagDecl *TD = ReturnType->getAsTagDecl()) if (const auto *A = TD->getAttr<WarnUnusedResultAttr>()) return {TD, A}; - for (const auto *TD = getCallReturnType(Ctx)->getAs<TypedefType>(); TD; + for (const auto *TD = ReturnType->getAs<TypedefType>(); TD; TD = TD->desugar()->getAs<TypedefType>()) if (const auto *A = TD->getDecl()->getAttr<WarnUnusedResultAttr>()) return {TD->getDecl(), A}; @@ -2844,12 +2844,11 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc, return true; } - if (const ObjCMethodDecl *MD = ME->getMethodDecl()) - if (MD->hasAttr<WarnUnusedResultAttr>()) { - WarnE = this; - Loc = getExprLoc(); - return true; - } + if (ME->hasUnusedResultAttr(Ctx)) { + WarnE = this; + Loc = getExprLoc(); + return true; + } return false; } diff --git a/clang/lib/AST/ExprObjC.cpp b/clang/lib/AST/ExprObjC.cpp index 50d3a447..83419a1 100644 --- a/clang/lib/AST/ExprObjC.cpp +++ b/clang/lib/AST/ExprObjC.cpp @@ -12,6 +12,7 @@ #include "clang/AST/ExprObjC.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/Attr.h" #include "clang/AST/ComputeDependence.h" #include "clang/AST/SelectorLocationsKind.h" #include "clang/AST/Type.h" diff --git a/clang/lib/AST/OSLog.cpp b/clang/lib/AST/OSLog.cpp index b777d4d..91f8410 100644 --- a/clang/lib/AST/OSLog.cpp +++ b/clang/lib/AST/OSLog.cpp @@ -1,4 +1,16 @@ -// TODO: header template +//===--- OSLog.cpp - OS log format string analysis ------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file implements analysis functions for OS log format strings and +/// buffer layout computation for __builtin_os_log_format and related builtins. +/// +//===----------------------------------------------------------------------===// #include "clang/AST/OSLog.h" #include "clang/AST/Attr.h" @@ -137,8 +149,8 @@ public: for (auto &Data : ArgsData) { if (!Data.MaskType.empty()) { CharUnits Size = CharUnits::fromQuantity(8); - Layout.Items.emplace_back(OSLogBufferItem::MaskKind, nullptr, - Size, 0, Data.MaskType); + Layout.Items.emplace_back(OSLogBufferItem::MaskKind, nullptr, Size, 0, + Data.MaskType); } if (Data.FieldWidth) { diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp index 7ff5f26..64dc1ce 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp @@ -949,7 +949,6 @@ LValue CIRGenFunction::emitCastLValue(const CastExpr *e) { case CK_Dynamic: case CK_ToUnion: case CK_BaseToDerived: - case CK_LValueBitCast: case CK_AddressSpaceConversion: case CK_ObjCObjectLValueCast: case CK_VectorSplat: @@ -965,6 +964,18 @@ LValue CIRGenFunction::emitCastLValue(const CastExpr *e) { return {}; } + case CK_LValueBitCast: { + // This must be a reinterpret_cast (or c-style equivalent). + const auto *ce = cast<ExplicitCastExpr>(e); + + cgm.emitExplicitCastExprType(ce, this); + LValue LV = emitLValue(e->getSubExpr()); + Address V = LV.getAddress().withElementType( + builder, convertTypeForMem(ce->getTypeAsWritten()->getPointeeType())); + + return makeAddrLValue(V, e->getType(), LV.getBaseInfo()); + } + case CK_NoOp: { // CK_NoOp can model a qualification conversion, which can remove an array // bound and change the IR type. diff --git a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp index d8459b4..51aab95 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp @@ -438,8 +438,7 @@ void AggExprEmitter::visitCXXParenListOrInitListExpr( // Push a destructor if necessary. // FIXME: if we have an array of structures, all explicitly // initialized, we can end up pushing a linear number of cleanups. - if (QualType::DestructionKind dtorKind = - field->getType().isDestructedType()) { + if (field->getType().isDestructedType()) { cgf.cgm.errorNYI(e->getSourceRange(), "visitCXXParenListOrInitListExpr destructor"); return; diff --git a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp index 02685a3..a09d739 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp @@ -189,8 +189,11 @@ mlir::Value ComplexExprEmitter::emitCast(CastKind ck, Expr *op, } case CK_LValueBitCast: { - cgf.cgm.errorNYI("ComplexExprEmitter::emitCast CK_LValueBitCast"); - return {}; + LValue origLV = cgf.emitLValue(op); + Address addr = + origLV.getAddress().withElementType(builder, cgf.convertType(destTy)); + LValue destLV = cgf.makeAddrLValue(addr, destTy); + return emitLoadOfLValue(destLV, op->getExprLoc()); } case CK_LValueToRValueBitCast: { diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp index b4b95d6..c65d025 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp @@ -923,4 +923,130 @@ CIRGenFunction::emitArrayLength(const clang::ArrayType *origArrayType, return builder.getConstInt(*currSrcLoc, SizeTy, countFromCLAs); } +// TODO(cir): Most of this function can be shared between CIRGen +// and traditional LLVM codegen +void CIRGenFunction::emitVariablyModifiedType(QualType type) { + assert(type->isVariablyModifiedType() && + "Must pass variably modified type to EmitVLASizes!"); + + // We're going to walk down into the type and look for VLA + // expressions. + do { + assert(type->isVariablyModifiedType()); + + const Type *ty = type.getTypePtr(); + switch (ty->getTypeClass()) { + case Type::CountAttributed: + case Type::PackIndexing: + case Type::ArrayParameter: + case Type::HLSLAttributedResource: + case Type::HLSLInlineSpirv: + case Type::PredefinedSugar: + cgm.errorNYI("CIRGenFunction::emitVariablyModifiedType"); + +#define TYPE(Class, Base) +#define ABSTRACT_TYPE(Class, Base) +#define NON_CANONICAL_TYPE(Class, Base) +#define DEPENDENT_TYPE(Class, Base) case Type::Class: +#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) +#include "clang/AST/TypeNodes.inc" + llvm_unreachable( + "dependent type must be resolved before the CIR codegen"); + + // These types are never variably-modified. + case Type::Builtin: + case Type::Complex: + case Type::Vector: + case Type::ExtVector: + case Type::ConstantMatrix: + case Type::Record: + case Type::Enum: + case Type::Using: + case Type::TemplateSpecialization: + case Type::ObjCTypeParam: + case Type::ObjCObject: + case Type::ObjCInterface: + case Type::ObjCObjectPointer: + case Type::BitInt: + llvm_unreachable("type class is never variably-modified!"); + + case Type::Elaborated: + type = cast<clang::ElaboratedType>(ty)->getNamedType(); + break; + + case Type::Adjusted: + type = cast<clang::AdjustedType>(ty)->getAdjustedType(); + break; + + case Type::Decayed: + type = cast<clang::DecayedType>(ty)->getPointeeType(); + break; + + case Type::Pointer: + type = cast<clang::PointerType>(ty)->getPointeeType(); + break; + + case Type::BlockPointer: + type = cast<clang::BlockPointerType>(ty)->getPointeeType(); + break; + + case Type::LValueReference: + case Type::RValueReference: + type = cast<clang::ReferenceType>(ty)->getPointeeType(); + break; + + case Type::MemberPointer: + type = cast<clang::MemberPointerType>(ty)->getPointeeType(); + break; + + case Type::ConstantArray: + case Type::IncompleteArray: + // Losing element qualification here is fine. + type = cast<clang::ArrayType>(ty)->getElementType(); + break; + + case Type::VariableArray: { + cgm.errorNYI("CIRGenFunction::emitVariablyModifiedType VLA"); + break; + } + + case Type::FunctionProto: + case Type::FunctionNoProto: + type = cast<clang::FunctionType>(ty)->getReturnType(); + break; + + case Type::Paren: + case Type::TypeOf: + case Type::UnaryTransform: + case Type::Attributed: + case Type::BTFTagAttributed: + case Type::SubstTemplateTypeParm: + case Type::MacroQualified: + // Keep walking after single level desugaring. + type = type.getSingleStepDesugaredType(getContext()); + break; + + case Type::Typedef: + case Type::Decltype: + case Type::Auto: + case Type::DeducedTemplateSpecialization: + // Stop walking: nothing to do. + return; + + case Type::TypeOfExpr: + // Stop walking: emit typeof expression. + emitIgnoredExpr(cast<clang::TypeOfExprType>(ty)->getUnderlyingExpr()); + return; + + case Type::Atomic: + type = cast<clang::AtomicType>(ty)->getValueType(); + break; + + case Type::Pipe: + type = cast<clang::PipeType>(ty)->getElementType(); + break; + } + } while (type->isVariablyModifiedType()); +} + } // namespace clang::CIRGen diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h index 4891c74..77539d7 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -1201,6 +1201,8 @@ public: /// inside a function, including static vars etc. void emitVarDecl(const clang::VarDecl &d); + void emitVariablyModifiedType(QualType ty); + mlir::LogicalResult emitWhileStmt(const clang::WhileStmt &s); /// Given an assignment `*lhs = rhs`, emit a test that checks if \p rhs is diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp index 3502705..0724cb1 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -1208,6 +1208,15 @@ cir::GlobalOp CIRGenModule::getGlobalForStringLiteral(const StringLiteral *s, return gv; } +void CIRGenModule::emitExplicitCastExprType(const ExplicitCastExpr *e, + CIRGenFunction *cgf) { + if (cgf && e->getType()->isVariablyModifiedType()) + cgf->emitVariablyModifiedType(e->getType()); + + assert(!cir::MissingFeatures::generateDebugInfo() && + "emitExplicitCastExprType"); +} + void CIRGenModule::emitDeclContext(const DeclContext *dc) { for (Decl *decl : dc->decls()) { // Unlike other DeclContexts, the contents of an ObjCImplDecl at TU scope diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h b/clang/lib/CIR/CodeGen/CIRGenModule.h index 16922b1..22519ff 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.h +++ b/clang/lib/CIR/CodeGen/CIRGenModule.h @@ -252,6 +252,11 @@ public: getAddrOfGlobal(clang::GlobalDecl gd, ForDefinition_t isForDefinition = NotForDefinition); + /// Emit type info if type of an expression is a variably modified + /// type. Also emit proper debug info for cast types. + void emitExplicitCastExprType(const ExplicitCastExpr *e, + CIRGenFunction *cgf = nullptr); + /// Emit code for a single global function or variable declaration. Forward /// declarations are emitted lazily. void emitGlobal(clang::GlobalDecl gd); diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index 9c36a43..2213c75 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -339,7 +339,7 @@ static LogicalResult checkConstantTypes(mlir::Operation *op, mlir::Type opType, } if (mlir::isa<cir::ConstArrayAttr, cir::ConstVectorAttr, - cir::ConstComplexAttr>(attrType)) + cir::ConstComplexAttr, cir::PoisonAttr>(attrType)) return success(); assert(isa<TypedAttr>(attrType) && "What else could we be looking at here?"); @@ -629,6 +629,11 @@ static Value tryFoldCastChain(cir::CastOp op) { } OpFoldResult cir::CastOp::fold(FoldAdaptor adaptor) { + if (mlir::isa_and_present<cir::PoisonAttr>(adaptor.getSrc())) { + // Propagate poison value + return cir::PoisonAttr::get(getContext(), getType()); + } + if (getSrc().getType() == getType()) { switch (getKind()) { case cir::CastKind::integral: { @@ -1783,6 +1788,12 @@ static bool isBoolNot(cir::UnaryOp op) { // // and the argument of the first one (%0) will be used instead. OpFoldResult cir::UnaryOp::fold(FoldAdaptor adaptor) { + if (auto poison = + mlir::dyn_cast_if_present<cir::PoisonAttr>(adaptor.getInput())) { + // Propagate poison values + return poison; + } + if (isBoolNot(*this)) if (auto previous = dyn_cast_or_null<UnaryOp>(getInput().getDefiningOp())) if (isBoolNot(previous)) @@ -2239,16 +2250,18 @@ static OpFoldResult foldUnaryBitOp(mlir::Attribute inputAttr, llvm::function_ref<llvm::APInt(const llvm::APInt &)> func, bool poisonZero = false) { + if (mlir::isa_and_present<cir::PoisonAttr>(inputAttr)) { + // Propagate poison value + return inputAttr; + } + auto input = mlir::dyn_cast_if_present<IntAttr>(inputAttr); if (!input) return nullptr; llvm::APInt inputValue = input.getValue(); - if (poisonZero && inputValue.isZero()) { - // TODO(cir): maybe we should return a poison value here? - assert(!MissingFeatures::poisonAttr()); - return nullptr; - } + if (poisonZero && inputValue.isZero()) + return cir::PoisonAttr::get(input.getType()); llvm::APInt resultValue = func(inputValue); return IntAttr::get(input.getType(), resultValue); @@ -2307,6 +2320,12 @@ OpFoldResult ByteSwapOp::fold(FoldAdaptor adaptor) { } OpFoldResult RotateOp::fold(FoldAdaptor adaptor) { + if (mlir::isa_and_present<cir::PoisonAttr>(adaptor.getInput()) || + mlir::isa_and_present<cir::PoisonAttr>(adaptor.getAmount())) { + // Propagate poison values + return cir::PoisonAttr::get(getType()); + } + auto input = mlir::dyn_cast_if_present<IntAttr>(adaptor.getInput()); auto amount = mlir::dyn_cast_if_present<IntAttr>(adaptor.getAmount()); if (!input && !amount) diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 3cd7de0..c27b889 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -1027,6 +1027,12 @@ mlir::LogicalResult CIRToLLVMConstantOpLowering::matchAndRewrite( mlir::ConversionPatternRewriter &rewriter) const { mlir::Attribute attr = op.getValue(); + if (mlir::isa<cir::PoisonAttr>(attr)) { + rewriter.replaceOpWithNewOp<mlir::LLVM::PoisonOp>( + op, getTypeConverter()->convertType(op.getType())); + return mlir::success(); + } + if (mlir::isa<mlir::IntegerType>(op.getType())) { // Verified cir.const operations cannot actually be of these types, but the // lowering pass may generate temporary cir.const operations with these diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp index 1b72578..0b8b824 100644 --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -1027,12 +1027,6 @@ void EmitAssemblyHelper::RunOptimizationPipeline( MPM.addPass( createModuleToFunctionPassAdaptor(ObjCARCExpandPass())); }); - PB.registerPipelineEarlySimplificationEPCallback( - [](ModulePassManager &MPM, OptimizationLevel Level, - ThinOrFullLTOPhase) { - if (Level != OptimizationLevel::O0) - MPM.addPass(ObjCARCAPElimPass()); - }); PB.registerScalarOptimizerLateEPCallback( [](FunctionPassManager &FPM, OptimizationLevel Level) { if (Level != OptimizationLevel::O0) diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index a371b67..77fc3a2 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -6435,7 +6435,7 @@ CodeGenFunction::LexicalScope::~LexicalScope() { static std::string SanitizerHandlerToCheckLabel(SanitizerHandler Handler) { std::string Label; switch (Handler) { -#define SANITIZER_CHECK(Enum, Name, Version) \ +#define SANITIZER_CHECK(Enum, Name, Version, Msg) \ case Enum: \ Label = "__ubsan_check_" #Name; \ break; diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 85c7688..90aed79 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -85,6 +85,16 @@ enum VariableTypeDescriptorKind : uint16_t { // Miscellaneous Helper Methods //===--------------------------------------------------------------------===// +static llvm::StringRef GetUBSanTrapForHandler(SanitizerHandler ID) { + switch (ID) { +#define SANITIZER_CHECK(Enum, Name, Version, Msg) \ + case SanitizerHandler::Enum: \ + return Msg; + LIST_SANITIZER_CHECKS +#undef SANITIZER_CHECK + } +} + /// CreateTempAlloca - This creates a alloca and inserts it into the entry /// block. RawAddress @@ -3649,7 +3659,7 @@ struct SanitizerHandlerInfo { } const SanitizerHandlerInfo SanitizerHandlers[] = { -#define SANITIZER_CHECK(Enum, Name, Version) {#Name, Version}, +#define SANITIZER_CHECK(Enum, Name, Version, Msg) {#Name, Version}, LIST_SANITIZER_CHECKS #undef SANITIZER_CHECK }; @@ -3954,6 +3964,8 @@ void CodeGenFunction::EmitCfiCheckFail() { StartFunction(GlobalDecl(), CGM.getContext().VoidTy, F, FI, Args, SourceLocation()); + ApplyDebugLocation ADL = ApplyDebugLocation::CreateArtificial(*this); + // This function is not affected by NoSanitizeList. This function does // not have a source location, but "src:*" would still apply. Revert any // changes to SanOpts made in StartFunction. @@ -4051,6 +4063,15 @@ void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked, llvm::BasicBlock *&TrapBB = TrapBBs[CheckHandlerID]; + llvm::DILocation *TrapLocation = Builder.getCurrentDebugLocation(); + llvm::StringRef TrapMessage = GetUBSanTrapForHandler(CheckHandlerID); + + if (getDebugInfo() && !TrapMessage.empty() && + CGM.getCodeGenOpts().SanitizeDebugTrapReasons && TrapLocation) { + TrapLocation = getDebugInfo()->CreateTrapFailureMessageFor( + TrapLocation, "Undefined Behavior Sanitizer", TrapMessage); + } + NoMerge = NoMerge || !CGM.getCodeGenOpts().OptimizationLevel || (CurCodeDecl && CurCodeDecl->hasAttr<OptimizeNoneAttr>()); @@ -4059,8 +4080,8 @@ void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked, auto Call = TrapBB->begin(); assert(isa<llvm::CallInst>(Call) && "Expected call in trap BB"); - Call->applyMergedLocation(Call->getDebugLoc(), - Builder.getCurrentDebugLocation()); + Call->applyMergedLocation(Call->getDebugLoc(), TrapLocation); + Builder.CreateCondBr(Checked, Cont, TrapBB, MDHelper.createLikelyBranchWeights()); } else { @@ -4069,6 +4090,8 @@ void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked, MDHelper.createLikelyBranchWeights()); EmitBlock(TrapBB); + ApplyDebugLocation applyTrapDI(*this, TrapLocation); + llvm::CallInst *TrapCall = Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::ubsantrap), llvm::ConstantInt::get(CGM.Int8Ty, CheckHandlerID)); diff --git a/clang/lib/CodeGen/SanitizerHandler.h b/clang/lib/CodeGen/SanitizerHandler.h index bb42e39..a66e7ab 100644 --- a/clang/lib/CodeGen/SanitizerHandler.h +++ b/clang/lib/CodeGen/SanitizerHandler.h @@ -14,35 +14,69 @@ #define LLVM_CLANG_LIB_CODEGEN_SANITIZER_HANDLER_H #define LIST_SANITIZER_CHECKS \ - SANITIZER_CHECK(AddOverflow, add_overflow, 0) \ - SANITIZER_CHECK(BuiltinUnreachable, builtin_unreachable, 0) \ - SANITIZER_CHECK(CFICheckFail, cfi_check_fail, 0) \ - SANITIZER_CHECK(DivremOverflow, divrem_overflow, 0) \ - SANITIZER_CHECK(DynamicTypeCacheMiss, dynamic_type_cache_miss, 0) \ - SANITIZER_CHECK(FloatCastOverflow, float_cast_overflow, 0) \ - SANITIZER_CHECK(FunctionTypeMismatch, function_type_mismatch, 0) \ - SANITIZER_CHECK(ImplicitConversion, implicit_conversion, 0) \ - SANITIZER_CHECK(InvalidBuiltin, invalid_builtin, 0) \ - SANITIZER_CHECK(InvalidObjCCast, invalid_objc_cast, 0) \ - SANITIZER_CHECK(LoadInvalidValue, load_invalid_value, 0) \ - SANITIZER_CHECK(MissingReturn, missing_return, 0) \ - SANITIZER_CHECK(MulOverflow, mul_overflow, 0) \ - SANITIZER_CHECK(NegateOverflow, negate_overflow, 0) \ - SANITIZER_CHECK(NullabilityArg, nullability_arg, 0) \ - SANITIZER_CHECK(NullabilityReturn, nullability_return, 1) \ - SANITIZER_CHECK(NonnullArg, nonnull_arg, 0) \ - SANITIZER_CHECK(NonnullReturn, nonnull_return, 1) \ - SANITIZER_CHECK(OutOfBounds, out_of_bounds, 0) \ - SANITIZER_CHECK(PointerOverflow, pointer_overflow, 0) \ - SANITIZER_CHECK(ShiftOutOfBounds, shift_out_of_bounds, 0) \ - SANITIZER_CHECK(SubOverflow, sub_overflow, 0) \ - SANITIZER_CHECK(TypeMismatch, type_mismatch, 1) \ - SANITIZER_CHECK(AlignmentAssumption, alignment_assumption, 0) \ - SANITIZER_CHECK(VLABoundNotPositive, vla_bound_not_positive, 0) \ - SANITIZER_CHECK(BoundsSafety, bounds_safety, 0) + SANITIZER_CHECK(AddOverflow, add_overflow, 0, "Integer addition overflowed") \ + SANITIZER_CHECK(BuiltinUnreachable, builtin_unreachable, 0, \ + "_builtin_unreachable(), execution reached an unreachable " \ + "program point") \ + SANITIZER_CHECK(CFICheckFail, cfi_check_fail, 0, \ + "Control flow integrity check failed") \ + SANITIZER_CHECK(DivremOverflow, divrem_overflow, 0, \ + "Integer divide or remainder overflowed") \ + SANITIZER_CHECK(DynamicTypeCacheMiss, dynamic_type_cache_miss, 0, \ + "Dynamic type cache miss, member call made on an object " \ + "whose dynamic type differs from the expected type") \ + SANITIZER_CHECK(FloatCastOverflow, float_cast_overflow, 0, \ + "Floating-point to integer conversion overflowed") \ + SANITIZER_CHECK(FunctionTypeMismatch, function_type_mismatch, 0, \ + "Function called with mismatched signature") \ + SANITIZER_CHECK(ImplicitConversion, implicit_conversion, 0, \ + "Implicit integer conversion overflowed or lost data") \ + SANITIZER_CHECK(InvalidBuiltin, invalid_builtin, 0, \ + "Invalid use of builtin function") \ + SANITIZER_CHECK(InvalidObjCCast, invalid_objc_cast, 0, \ + "Invalid Objective-C cast") \ + SANITIZER_CHECK(LoadInvalidValue, load_invalid_value, 0, \ + "Loaded an invalid or uninitialized value for the type") \ + SANITIZER_CHECK(MissingReturn, missing_return, 0, \ + "Execution reached the end of a value-returning function " \ + "without returning a value") \ + SANITIZER_CHECK(MulOverflow, mul_overflow, 0, \ + "Integer multiplication overflowed") \ + SANITIZER_CHECK(NegateOverflow, negate_overflow, 0, \ + "Integer negation overflowed") \ + SANITIZER_CHECK( \ + NullabilityArg, nullability_arg, 0, \ + "Passing null as an argument which is annotated with _Nonnull") \ + SANITIZER_CHECK(NullabilityReturn, nullability_return, 1, \ + "Returning null from a function with a return type " \ + "annotated with _Nonnull") \ + SANITIZER_CHECK(NonnullArg, nonnull_arg, 0, \ + "Passing null pointer as an argument which is declared to " \ + "never be null") \ + SANITIZER_CHECK(NonnullReturn, nonnull_return, 1, \ + "Returning null pointer from a function which is declared " \ + "to never return null") \ + SANITIZER_CHECK(OutOfBounds, out_of_bounds, 0, "Array index out of bounds") \ + SANITIZER_CHECK(PointerOverflow, pointer_overflow, 0, \ + "Pointer arithmetic overflowed bounds") \ + SANITIZER_CHECK(ShiftOutOfBounds, shift_out_of_bounds, 0, \ + "Shift exponent is too large for the type") \ + SANITIZER_CHECK(SubOverflow, sub_overflow, 0, \ + "Integer subtraction overflowed") \ + SANITIZER_CHECK(TypeMismatch, type_mismatch, 1, \ + "Type mismatch in operation") \ + SANITIZER_CHECK(AlignmentAssumption, alignment_assumption, 0, \ + "Alignment assumption violated") \ + SANITIZER_CHECK( \ + VLABoundNotPositive, vla_bound_not_positive, 0, \ + "Variable length array bound evaluates to non-positive value") \ + SANITIZER_CHECK(BoundsSafety, bounds_safety, 0, \ + "") // BoundsSafety Msg is empty because it is not considered + // part of UBSan; therefore, no trap reason is emitted for + // this case. enum SanitizerHandler { -#define SANITIZER_CHECK(Enum, Name, Version) Enum, +#define SANITIZER_CHECK(Enum, Name, Version, Msg) Enum, LIST_SANITIZER_CHECKS #undef SANITIZER_CHECK }; diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index 853f694..99de951 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -910,7 +910,7 @@ getSystemOffloadArchs(Compilation &C, Action::OffloadKind Kind) { SmallVector<std::string> GPUArchs; if (llvm::ErrorOr<std::string> Executable = - llvm::sys::findProgramByName(Program)) { + llvm::sys::findProgramByName(Program, {C.getDriver().Dir})) { llvm::SmallVector<StringRef> Args{*Executable}; if (Kind == Action::OFK_HIP) Args.push_back("--only=amdgpu"); @@ -4919,13 +4919,14 @@ Action *Driver::BuildOffloadingActions(Compilation &C, } // HIP code in device-only non-RDC mode will bundle the output if it invoked - // the linker. + // the linker or if the user explicitly requested it. bool ShouldBundleHIP = - HIPNoRDC && offloadDeviceOnly() && Args.hasFlag(options::OPT_gpu_bundle_output, - options::OPT_no_gpu_bundle_output, true) && - !llvm::any_of(OffloadActions, - [](Action *A) { return A->getType() != types::TY_Image; }); + options::OPT_no_gpu_bundle_output, false) || + (HIPNoRDC && offloadDeviceOnly() && + llvm::none_of(OffloadActions, [](Action *A) { + return A->getType() != types::TY_Image; + })); // All kinds exit now in device-only mode except for non-RDC mode HIP. if (offloadDeviceOnly() && !ShouldBundleHIP) diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp index 21e4cff..98793a5 100644 --- a/clang/lib/Driver/SanitizerArgs.cpp +++ b/clang/lib/Driver/SanitizerArgs.cpp @@ -1382,6 +1382,12 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, CmdArgs.push_back(Args.MakeArgString("-fsanitize-annotate-debug-info=" + toString(AnnotateDebugInfo))); + if (const Arg *A = + Args.getLastArg(options::OPT_fsanitize_debug_trap_reasons, + options::OPT_fno_sanitize_debug_trap_reasons)) { + CmdArgs.push_back(Args.MakeArgString(A->getAsString(Args))); + } + addSpecialCaseListOpt(Args, CmdArgs, "-fsanitize-ignorelist=", UserIgnorelistFiles); addSpecialCaseListOpt(Args, CmdArgs, diff --git a/clang/lib/Driver/ToolChains/HIPSPV.cpp b/clang/lib/Driver/ToolChains/HIPSPV.cpp index 643a67f..62bca04 100644 --- a/clang/lib/Driver/ToolChains/HIPSPV.cpp +++ b/clang/lib/Driver/ToolChains/HIPSPV.cpp @@ -69,8 +69,17 @@ void HIPSPV::Linker::constructLinkAndEmitSpirvCommand( // Link LLVM bitcode. ArgStringList LinkArgs{}; + for (auto Input : Inputs) LinkArgs.push_back(Input.getFilename()); + + // Add static device libraries using the common helper function. + // This handles unbundling archives (.a) containing bitcode bundles. + StringRef Arch = getToolChain().getTriple().getArchName(); + StringRef Target = + "generic"; // SPIR-V is generic, no specific target ID like -mcpu + tools::AddStaticDeviceLibsLinking(C, *this, JA, Inputs, Args, LinkArgs, Arch, + Target, /*IsBitCodeSDL=*/true); LinkArgs.append({"-o", TempFile}); const char *LlvmLink = Args.MakeArgString(getToolChain().GetProgramPath("llvm-link")); diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index e6808f7..0637807 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -2639,32 +2639,44 @@ private: int countVariableAlignments(const SmallVectorImpl<AnnotatedLine *> &Lines) { int AlignmentDiff = 0; + for (const AnnotatedLine *Line : Lines) { AlignmentDiff += countVariableAlignments(Line->Children); - for (FormatToken *Tok = Line->First; Tok && Tok->Next; Tok = Tok->Next) { + + for (const auto *Tok = Line->getFirstNonComment(); Tok; Tok = Tok->Next) { if (Tok->isNot(TT_PointerOrReference)) continue; - // Don't treat space in `void foo() &&` or `void() &&` as evidence. - if (const auto *Prev = Tok->getPreviousNonComment()) { - if (Prev->is(tok::r_paren) && Prev->MatchingParen) { - if (const auto *Func = - Prev->MatchingParen->getPreviousNonComment()) { - if (Func->isOneOf(TT_FunctionDeclarationName, TT_StartOfName, - TT_OverloadedOperator) || - Func->isTypeName(LangOpts)) { - continue; - } - } - } + + const auto *Prev = Tok->Previous; + const bool PrecededByName = Prev && Prev->Tok.getIdentifierInfo(); + const bool SpaceBefore = Tok->hasWhitespaceBefore(); + + // e.g. `int **`, `int*&`, etc. + while (Tok->Next && Tok->Next->is(TT_PointerOrReference)) + Tok = Tok->Next; + + const auto *Next = Tok->Next; + const bool FollowedByName = Next && Next->Tok.getIdentifierInfo(); + const bool SpaceAfter = Next && Next->hasWhitespaceBefore(); + + if ((!PrecededByName && !FollowedByName) || + // e.g. `int * i` or `int*i` + (PrecededByName && FollowedByName && SpaceBefore == SpaceAfter)) { + continue; } - bool SpaceBefore = Tok->hasWhitespaceBefore(); - bool SpaceAfter = Tok->Next->hasWhitespaceBefore(); - if (SpaceBefore && !SpaceAfter) + + if ((PrecededByName && SpaceBefore) || + (FollowedByName && !SpaceAfter)) { + // Right alignment. ++AlignmentDiff; - if (!SpaceBefore && SpaceAfter) + } else if ((PrecededByName && !SpaceBefore) || + (FollowedByName && SpaceAfter)) { + // Left alignment. --AlignmentDiff; + } } } + return AlignmentDiff; } diff --git a/clang/lib/Headers/opencl-c-base.h b/clang/lib/Headers/opencl-c-base.h index 2b7f504..6206a34 100644 --- a/clang/lib/Headers/opencl-c-base.h +++ b/clang/lib/Headers/opencl-c-base.h @@ -697,7 +697,16 @@ template <typename _Tp> struct __remove_address_space<__constant _Tp> { #if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_1_2) // OpenCL v1.2 s6.12.13, v2.0 s6.13.13 - printf -int printf(__constant const char* st, ...) __attribute__((format(printf, 1, 2))); +#ifdef __OPENCL_CPP_VERSION__ +#define CLINKAGE extern "C" +#else +#define CLINKAGE +#endif + +CLINKAGE int printf(__constant const char *st, ...) + __attribute__((format(printf, 1, 2))); + +#undef CLINKAGE #endif #ifdef cl_intel_device_side_avc_motion_estimation diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp index 890567c..6f12ac8 100644 --- a/clang/lib/Lex/PPMacroExpansion.cpp +++ b/clang/lib/Lex/PPMacroExpansion.cpp @@ -1760,7 +1760,8 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { Tok, *this, diag::err_feature_check_malformed); if (!II) return false; - else if (II->getBuiltinID() != 0) { + unsigned BuiltinID = II->getBuiltinID(); + if (BuiltinID != 0) { switch (II->getBuiltinID()) { case Builtin::BI__builtin_cpu_is: return getTargetInfo().supportsCpuIs(); @@ -1774,8 +1775,11 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { // usual allocation and deallocation functions. Required by libc++ return 201802; default: + // __has_builtin should return false for aux builtins. + if (getBuiltinInfo().isAuxBuiltinID(BuiltinID)) + return false; return Builtin::evaluateRequiredTargetFeatures( - getBuiltinInfo().getRequiredFeatures(II->getBuiltinID()), + getBuiltinInfo().getRequiredFeatures(BuiltinID), getTargetInfo().getTargetOpts().FeatureMap); } return true; diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 56608e9..d50eeff 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -1616,6 +1616,8 @@ void Sema::ActOnEndOfTranslationUnit() { if (!PP.isIncrementalProcessingEnabled()) TUScope = nullptr; + + checkExposure(Context.getTranslationUnitDecl()); } diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index a4e8de4..16b18bc 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -4805,10 +4805,10 @@ void Sema::AddModeAttr(Decl *D, const AttributeCommonInfo &CI, static void handleNonStringAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // This only applies to fields and variable declarations which have an array - // type. + // type or pointer type, with character elements. QualType QT = cast<ValueDecl>(D)->getType(); - if (!QT->isArrayType() || - !QT->getBaseElementTypeUnsafe()->isAnyCharacterType()) { + if ((!QT->isArrayType() && !QT->isPointerType()) || + !QT->getPointeeOrArrayElementType()->isAnyCharacterType()) { S.Diag(D->getBeginLoc(), diag::warn_attribute_non_character_array) << AL << AL.isRegularKeywordAttribute() << QT << AL.getRange(); return; diff --git a/clang/lib/Sema/SemaModule.cpp b/clang/lib/Sema/SemaModule.cpp index 7c982bc..98ebd70 100644 --- a/clang/lib/Sema/SemaModule.cpp +++ b/clang/lib/Sema/SemaModule.cpp @@ -13,6 +13,7 @@ #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTMutationListener.h" +#include "clang/AST/RecursiveASTVisitor.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/ParsedAttr.h" @@ -485,6 +486,7 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc, // implementation unit importing its interface). Make this module visible // and return the import decl to be added to the current TU. if (Interface) { + HadImportedNamedModules = true; makeTransitiveImportsVisible(getASTContext(), VisibleModules, Interface, Mod, ModuleLoc, @@ -728,6 +730,8 @@ DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc, getCurrentModule()->Imports.insert(Mod); } + HadImportedNamedModules = true; + return Import; } @@ -1102,3 +1106,471 @@ bool Sema::isCurrentModulePurview() const { return false; } } + +//===----------------------------------------------------------------------===// +// Checking Exposure in modules // +//===----------------------------------------------------------------------===// + +namespace { +class ExposureChecker { +public: + ExposureChecker(Sema &S) : SemaRef(S) {} + + bool checkExposure(const VarDecl *D, bool Diag); + bool checkExposure(const CXXRecordDecl *D, bool Diag); + bool checkExposure(const Stmt *S, bool Diag); + bool checkExposure(const FunctionDecl *D, bool Diag); + bool checkExposure(const NamedDecl *D, bool Diag); + void checkExposureInContext(const DeclContext *DC); + bool isExposureCandidate(const NamedDecl *D); + + bool isTULocal(QualType Ty); + bool isTULocal(const NamedDecl *ND); + bool isTULocal(const Expr *E); + + Sema &SemaRef; + +private: + llvm::DenseSet<const NamedDecl *> ExposureSet; + llvm::DenseSet<const NamedDecl *> KnownNonExposureSet; +}; + +bool ExposureChecker::isTULocal(QualType Ty) { + // [basic.link]p15: + // An entity is TU-local if it is + // - a type, type alias, namespace, namespace alias, function, variable, or + // template that + // -- has internal linkage, or + return Ty->getLinkage() == Linkage::Internal; + + // TODO: + // [basic.link]p15.2: + // a type with no name that is defined outside a class-specifier, function + // body, or initializer or is introduced by a defining-type-specifier that + // is used to declare only TU-local entities, +} + +bool ExposureChecker::isTULocal(const NamedDecl *D) { + if (!D) + return false; + + // [basic.link]p15: + // An entity is TU-local if it is + // - a type, type alias, namespace, namespace alias, function, variable, or + // template that + // -- has internal linkage, or + if (D->getLinkageInternal() == Linkage::Internal) + return true; + + if (D->isInAnonymousNamespace()) + return true; + + // [basic.link]p15.1.2: + // does not have a name with linkage and is declared, or introduced by a + // lambda-expression, within the definition of a TU-local entity, + if (D->getLinkageInternal() == Linkage::None) + if (auto *ND = dyn_cast<NamedDecl>(D->getDeclContext()); + ND && isTULocal(ND)) + return true; + + // [basic.link]p15.3, p15.4: + // - a specialization of a TU-local template, + // - a specialization of a template with any TU-local template argument, or + ArrayRef<TemplateArgument> TemplateArgs; + NamedDecl *PrimaryTemplate = nullptr; + if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D)) { + TemplateArgs = CTSD->getTemplateArgs().asArray(); + PrimaryTemplate = CTSD->getSpecializedTemplate(); + if (isTULocal(PrimaryTemplate)) + return true; + } else if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(D)) { + TemplateArgs = VTSD->getTemplateArgs().asArray(); + PrimaryTemplate = VTSD->getSpecializedTemplate(); + if (isTULocal(PrimaryTemplate)) + return true; + } else if (auto *FD = dyn_cast<FunctionDecl>(D)) { + if (auto *TAList = FD->getTemplateSpecializationArgs()) + TemplateArgs = TAList->asArray(); + + PrimaryTemplate = FD->getPrimaryTemplate(); + if (isTULocal(PrimaryTemplate)) + return true; + } + + if (!PrimaryTemplate) + // Following off, we only check for specializations. + return false; + + if (KnownNonExposureSet.count(D)) + return false; + + for (auto &TA : TemplateArgs) { + switch (TA.getKind()) { + case TemplateArgument::Type: + if (isTULocal(TA.getAsType())) + return true; + break; + case TemplateArgument::Declaration: + if (isTULocal(TA.getAsDecl())) + return true; + break; + default: + break; + } + } + + // [basic.link]p15.5 + // - a specialization of a template whose (possibly instantiated) declaration + // is an exposure. + if (checkExposure(PrimaryTemplate, /*Diag=*/false)) + return true; + + // Avoid calling checkExposure again since it is expensive. + KnownNonExposureSet.insert(D); + return false; +} + +bool ExposureChecker::isTULocal(const Expr *E) { + if (!E) + return false; + + // [basic.link]p16: + // A value or object is TU-local if either + // - it is of TU-local type, + if (isTULocal(E->getType())) + return true; + + E = E->IgnoreParenImpCasts(); + // [basic.link]p16.2: + // - it is, or is a pointer to, a TU-local function or the object associated + // with a TU-local variable, + // - it is an object of class or array type and any of its subobjects or any + // of the objects or functions to which its non-static data members of + // reference type refer is TU-local and is usable in constant expressions, or + // FIXME: But how can we know the value of pointers or arrays at compile time? + if (const auto *DRE = dyn_cast<DeclRefExpr>(E)) { + if (auto *FD = dyn_cast_or_null<FunctionDecl>(DRE->getFoundDecl())) + return isTULocal(FD); + else if (auto *VD = dyn_cast_or_null<VarDecl>(DRE->getFoundDecl())) + return isTULocal(VD); + else if (auto *RD = dyn_cast_or_null<CXXRecordDecl>(DRE->getFoundDecl())) + return isTULocal(RD); + } + + // TODO: + // [basic.link]p16.4: + // it is a reflection value that represents... + + return false; +} + +bool ExposureChecker::isExposureCandidate(const NamedDecl *D) { + if (!D) + return false; + + // [basic.link]p17: + // If a (possibly instantiated) declaration of, or a deduction guide for, + // a non-TU-local entity in a module interface unit + // (outside the private-module-fragment, if any) or + // module partition is an exposure, the program is ill-formed. + Module *M = D->getOwningModule(); + if (!M || !M->isInterfaceOrPartition()) + return false; + + if (D->isImplicit()) + return false; + + // [basic.link]p14: + // A declaration is an exposure if it either names a TU-local entity + // (defined below), ignoring: + // ... + // - friend declarations in a class definition + if (D->getFriendObjectKind() && + isa<CXXRecordDecl>(D->getLexicalDeclContext())) + return false; + + return true; +} + +bool ExposureChecker::checkExposure(const NamedDecl *D, bool Diag) { + if (!isExposureCandidate(D)) + return false; + + if (auto *FD = dyn_cast<FunctionDecl>(D)) + return checkExposure(FD, Diag); + if (auto *FTD = dyn_cast<FunctionTemplateDecl>(D)) + return checkExposure(FTD->getTemplatedDecl(), Diag); + + if (auto *VD = dyn_cast<VarDecl>(D)) + return checkExposure(VD, Diag); + if (auto *VTD = dyn_cast<VarTemplateDecl>(D)) + return checkExposure(VTD->getTemplatedDecl(), Diag); + + if (auto *RD = dyn_cast<CXXRecordDecl>(D)) + return checkExposure(RD, Diag); + + if (auto *CTD = dyn_cast<ClassTemplateDecl>(D)) + return checkExposure(CTD->getTemplatedDecl(), Diag); + + return false; +} + +bool ExposureChecker::checkExposure(const FunctionDecl *FD, bool Diag) { + bool IsExposure = false; + if (isTULocal(FD->getReturnType())) { + IsExposure = true; + if (Diag) + SemaRef.Diag(FD->getReturnTypeSourceRange().getBegin(), + diag::warn_exposure) + << FD->getReturnType(); + } + + for (ParmVarDecl *Parms : FD->parameters()) + if (isTULocal(Parms->getType())) { + IsExposure = true; + if (Diag) + SemaRef.Diag(Parms->getLocation(), diag::warn_exposure) + << Parms->getType(); + } + + bool IsImplicitInstantiation = + FD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation; + + // [basic.link]p14: + // A declaration is an exposure if it either names a TU-local entity + // (defined below), ignoring: + // - the function-body for a non-inline function or function template + // (but not the deduced return + // type for a (possibly instantiated) definition of a function with a + // declared return type that uses a placeholder type + // ([dcl.spec.auto])), + Diag &= + (FD->isInlined() || IsImplicitInstantiation) && !FD->isDependentContext(); + + IsExposure |= checkExposure(FD->getBody(), Diag); + if (IsExposure) + ExposureSet.insert(FD); + + return IsExposure; +} + +bool ExposureChecker::checkExposure(const VarDecl *VD, bool Diag) { + bool IsExposure = false; + // [basic.link]p14: + // A declaration is an exposure if it either names a TU-local entity (defined + // below), ignoring: + // ... + // or defines a constexpr variable initialized to a TU-local value (defined + // below). + if (VD->isConstexpr() && isTULocal(VD->getInit())) { + IsExposure = true; + if (Diag) + SemaRef.Diag(VD->getInit()->getExprLoc(), diag::warn_exposure) + << VD->getInit(); + } + + if (isTULocal(VD->getType())) { + IsExposure = true; + if (Diag) + SemaRef.Diag(VD->getLocation(), diag::warn_exposure) << VD->getType(); + } + + // [basic.link]p14: + // ..., ignoring: + // - the initializer for a variable or variable template (but not the + // variable's type), + // + // Note: although the spec says to ignore the initializer for all variable, + // for the code we generated now for inline variables, it is dangerous if the + // initializer of an inline variable is TULocal. + Diag &= !VD->getDeclContext()->isDependentContext() && VD->isInline(); + IsExposure |= checkExposure(VD->getInit(), Diag); + if (IsExposure) + ExposureSet.insert(VD); + + return IsExposure; +} + +bool ExposureChecker::checkExposure(const CXXRecordDecl *RD, bool Diag) { + if (!RD->hasDefinition()) + return false; + + bool IsExposure = false; + for (CXXMethodDecl *Method : RD->methods()) + IsExposure |= checkExposure(Method, Diag); + + for (FieldDecl *FD : RD->fields()) { + if (isTULocal(FD->getType())) { + IsExposure = true; + if (Diag) + SemaRef.Diag(FD->getLocation(), diag::warn_exposure) << FD->getType(); + } + } + + for (const CXXBaseSpecifier &Base : RD->bases()) { + if (isTULocal(Base.getType())) { + IsExposure = true; + if (Diag) + SemaRef.Diag(Base.getBaseTypeLoc(), diag::warn_exposure) + << Base.getType(); + } + } + + if (IsExposure) + ExposureSet.insert(RD); + + return IsExposure; +} + +template <typename CallbackTy> +class ReferenceTULocalChecker + : public clang::RecursiveASTVisitor<ReferenceTULocalChecker<CallbackTy>> { +public: + ReferenceTULocalChecker(ExposureChecker &C, CallbackTy &&Callback) + : Checker(C), Callback(std::move(Callback)) {} + + bool VisitDeclRefExpr(DeclRefExpr *DRE) { + ValueDecl *Referenced = DRE->getDecl(); + if (!Referenced) + return true; + + if (!Checker.isTULocal(Referenced)) + // We don't care if the referenced declaration is not TU-local. + return true; + + Qualifiers Qual = DRE->getType().getQualifiers(); + // [basic.link]p14: + // A declaration is an exposure if it either names a TU-local entity + // (defined below), ignoring: + // ... + // - any reference to a non-volatile const object ... + if (Qual.hasConst() && !Qual.hasVolatile()) + return true; + + // [basic.link]p14: + // ..., ignoring: + // ... + // (p14.4) - ... or reference with internal or no linkage initialized with + // a constant expression that is not an odr-use + ASTContext &Context = Referenced->getASTContext(); + Linkage L = Referenced->getLinkageInternal(); + if (DRE->isNonOdrUse() && (L == Linkage::Internal || L == Linkage::None)) + if (auto *VD = dyn_cast<VarDecl>(Referenced); + VD && VD->getInit() && !VD->getInit()->isValueDependent() && + VD->getInit()->isConstantInitializer(Context, /*IsForRef=*/false)) + return true; + + Callback(DRE, Referenced); + return true; + } + + ExposureChecker &Checker; + CallbackTy Callback; +}; + +template <typename CallbackTy> +ReferenceTULocalChecker(ExposureChecker &, CallbackTy &&) + -> ReferenceTULocalChecker<CallbackTy>; + +bool ExposureChecker::checkExposure(const Stmt *S, bool Diag) { + if (!S) + return false; + + bool HasReferencedTULocals = false; + ReferenceTULocalChecker Checker( + *this, [this, &HasReferencedTULocals, Diag](DeclRefExpr *DRE, + ValueDecl *Referenced) { + if (Diag) { + SemaRef.Diag(DRE->getExprLoc(), diag::warn_exposure) << Referenced; + } + HasReferencedTULocals = true; + }); + Checker.TraverseStmt(const_cast<Stmt *>(S)); + return HasReferencedTULocals; +} + +void ExposureChecker::checkExposureInContext(const DeclContext *DC) { + for (auto *TopD : DC->noload_decls()) { + auto *TopND = dyn_cast<NamedDecl>(TopD); + if (!TopND) + continue; + + if (auto *Namespace = dyn_cast<NamespaceDecl>(TopND)) { + checkExposureInContext(Namespace); + continue; + } + + // [basic.link]p17: + // If a (possibly instantiated) declaration of, or a deduction guide for, + // a non-TU-local entity in a module interface unit + // (outside the private-module-fragment, if any) or + // module partition is an exposure, the program is ill-formed. + if (!TopND->isFromASTFile() && isExposureCandidate(TopND) && + !isTULocal(TopND)) + checkExposure(TopND, /*Diag=*/true); + } +} + +} // namespace + +void Sema::checkExposure(const TranslationUnitDecl *TU) { + if (!TU) + return; + + ExposureChecker Checker(*this); + + Module *M = TU->getOwningModule(); + if (M && M->isInterfaceOrPartition()) + Checker.checkExposureInContext(TU); + + // [basic.link]p18: + // If a declaration that appears in one translation unit names a TU-local + // entity declared in another translation unit that is not a header unit, + // the program is ill-formed. + for (auto FDAndInstantiationLocPair : PendingCheckReferenceForTULocal) { + FunctionDecl *FD = FDAndInstantiationLocPair.first; + SourceLocation PointOfInstantiation = FDAndInstantiationLocPair.second; + + if (!FD->hasBody()) + continue; + + ReferenceTULocalChecker(Checker, [&, this](DeclRefExpr *DRE, + ValueDecl *Referenced) { + // A "defect" in current implementation. Now an implicit instantiation of + // a template, the instantiation is considered to be in the same module + // unit as the template instead of the module unit where the instantiation + // happens. + // + // See test/Modules/Exposre-2.cppm for example. + if (!Referenced->isFromASTFile()) + return; + + if (!Referenced->isInAnotherModuleUnit()) + return; + + // This is not standard conforming. But given there are too many static + // (inline) functions in headers in existing code, it is more user + // friendly to ignore them temporarily now. maybe we can have another flag + // for this. + if (Referenced->getOwningModule()->isExplicitGlobalModule() && + isa<FunctionDecl>(Referenced)) + return; + + Diag(PointOfInstantiation, + diag::warn_reference_tu_local_entity_in_other_tu) + << FD << Referenced + << Referenced->getOwningModule()->getTopLevelModuleName(); + }).TraverseStmt(FD->getBody()); + } +} + +void Sema::checkReferenceToTULocalFromOtherTU( + FunctionDecl *FD, SourceLocation PointOfInstantiation) { + // Checking if a declaration have any reference to TU-local entities in other + // TU is expensive. Try to avoid it as much as possible. + if (!FD || !HadImportedNamedModules) + return; + + PendingCheckReferenceForTULocal.push_back( + std::make_pair(FD, PointOfInstantiation)); +} diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 5dd5b49..76e189d 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -8042,8 +8042,8 @@ static void AddTemplateOverloadCandidateImmediately( Candidate.IgnoreObjectArgument = isa<CXXMethodDecl>(Candidate.Function) && - cast<CXXMethodDecl>(Candidate.Function) - ->isImplicitObjectMemberFunction() && + !cast<CXXMethodDecl>(Candidate.Function) + ->isExplicitObjectMemberFunction() && !isa<CXXConstructorDecl>(Candidate.Function); Candidate.ExplicitCallArguments = Args.size(); diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index f85826a..3f89843 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -295,8 +295,7 @@ void DiagnoseUnused(Sema &S, const Expr *E, std::optional<unsigned> DiagID) { return; auto [OffendingDecl, A] = CE->getUnusedResultAttr(S.Context); - if (DiagnoseNoDiscard(S, OffendingDecl, - cast_or_null<WarnUnusedResultAttr>(A), Loc, R1, R2, + if (DiagnoseNoDiscard(S, OffendingDecl, A, Loc, R1, R2, /*isCtor=*/false)) return; @@ -344,13 +343,11 @@ void DiagnoseUnused(Sema &S, const Expr *E, std::optional<unsigned> DiagID) { S.Diag(Loc, diag::err_arc_unused_init_message) << R1; return; } - const ObjCMethodDecl *MD = ME->getMethodDecl(); - if (MD) { - if (DiagnoseNoDiscard(S, nullptr, MD->getAttr<WarnUnusedResultAttr>(), - Loc, R1, R2, - /*isCtor=*/false)) - return; - } + + auto [OffendingDecl, A] = ME->getUnusedResultAttr(S.Context); + if (DiagnoseNoDiscard(S, OffendingDecl, A, Loc, R1, R2, + /*isCtor=*/false)) + return; } else if (const PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(E)) { const Expr *Source = POE->getSyntacticForm(); // Handle the actually selected call of an OpenMP specialized call. diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index e2c3cdc..233bb65 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -5853,6 +5853,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, // context seems wrong. Investigate more. ActOnFinishFunctionBody(Function, Body.get(), /*IsInstantiation=*/true); + checkReferenceToTULocalFromOtherTU(Function, PointOfInstantiation); + PerformDependentDiagnostics(PatternDecl, TemplateArgs); if (auto *Listener = getASTMutationListener()) diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 10aedb6..f896f9f1 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -8488,6 +8488,7 @@ bool ASTReader::LoadExternalSpecializationsImpl(SpecLookupTableTy &SpecLookups, bool ASTReader::LoadExternalSpecializations(const Decl *D, bool OnlyPartial) { assert(D); + CompleteRedeclChain(D); bool NewSpecsFound = LoadExternalSpecializationsImpl(PartialSpecializationsLookups, D); if (OnlyPartial) diff --git a/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp index d7eea7e..152129e 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp @@ -25,18 +25,22 @@ using namespace clang; using namespace ento; namespace { + +class DerefBugType : public BugType { + StringRef ArrayMsg, FieldMsg; + +public: + DerefBugType(CheckerFrontend *FE, StringRef Desc, const char *AMsg, + const char *FMsg = nullptr) + : BugType(FE, Desc), ArrayMsg(AMsg), FieldMsg(FMsg ? FMsg : AMsg) {} + StringRef getArrayMsg() const { return ArrayMsg; } + StringRef getFieldMsg() const { return FieldMsg; } +}; + class DereferenceChecker - : public Checker< check::Location, - check::Bind, - EventDispatcher<ImplicitNullDerefEvent> > { - enum DerefKind { - NullPointer, - UndefinedPointerValue, - AddressOfLabel, - FixedAddress, - }; - - void reportBug(DerefKind K, ProgramStateRef State, const Stmt *S, + : public CheckerFamily<check::Location, check::Bind, + EventDispatcher<ImplicitNullDerefEvent>> { + void reportBug(const DerefBugType &BT, ProgramStateRef State, const Stmt *S, CheckerContext &C) const; bool suppressReport(CheckerContext &C, const Expr *E) const; @@ -52,13 +56,23 @@ public: const LocationContext *LCtx, bool loadedFrom = false); - bool CheckNullDereference = false; - bool CheckFixedDereference = false; - - std::unique_ptr<BugType> BT_Null; - std::unique_ptr<BugType> BT_Undef; - std::unique_ptr<BugType> BT_Label; - std::unique_ptr<BugType> BT_FixedAddress; + CheckerFrontend NullDerefChecker, FixedDerefChecker; + const DerefBugType NullBug{&NullDerefChecker, "Dereference of null pointer", + "a null pointer dereference", + "a dereference of a null pointer"}; + const DerefBugType UndefBug{&NullDerefChecker, + "Dereference of undefined pointer value", + "an undefined pointer dereference", + "a dereference of an undefined pointer value"}; + const DerefBugType LabelBug{&NullDerefChecker, + "Dereference of the address of a label", + "an undefined pointer dereference", + "a dereference of an address of a label"}; + const DerefBugType FixedAddressBug{&FixedDerefChecker, + "Dereference of a fixed address", + "a dereference of a fixed address"}; + + StringRef getDebugTag() const override { return "DereferenceChecker"; } }; } // end anonymous namespace @@ -158,115 +172,87 @@ static bool isDeclRefExprToReference(const Expr *E) { return false; } -void DereferenceChecker::reportBug(DerefKind K, ProgramStateRef State, - const Stmt *S, CheckerContext &C) const { - const BugType *BT = nullptr; - llvm::StringRef DerefStr1; - llvm::StringRef DerefStr2; - switch (K) { - case DerefKind::NullPointer: - if (!CheckNullDereference) { - C.addSink(); - return; - } - BT = BT_Null.get(); - DerefStr1 = " results in a null pointer dereference"; - DerefStr2 = " results in a dereference of a null pointer"; - break; - case DerefKind::UndefinedPointerValue: - if (!CheckNullDereference) { - C.addSink(); +void DereferenceChecker::reportBug(const DerefBugType &BT, + ProgramStateRef State, const Stmt *S, + CheckerContext &C) const { + if (&BT == &FixedAddressBug) { + if (!FixedDerefChecker.isEnabled()) + // Deliberately don't add a sink node if check is disabled. + // This situation may be valid in special cases. return; - } - BT = BT_Undef.get(); - DerefStr1 = " results in an undefined pointer dereference"; - DerefStr2 = " results in a dereference of an undefined pointer value"; - break; - case DerefKind::AddressOfLabel: - if (!CheckNullDereference) { + } else { + if (!NullDerefChecker.isEnabled()) { C.addSink(); return; } - BT = BT_Label.get(); - DerefStr1 = " results in an undefined pointer dereference"; - DerefStr2 = " results in a dereference of an address of a label"; - break; - case DerefKind::FixedAddress: - // Deliberately don't add a sink node if check is disabled. - // This situation may be valid in special cases. - if (!CheckFixedDereference) - return; - - BT = BT_FixedAddress.get(); - DerefStr1 = " results in a dereference of a fixed address"; - DerefStr2 = " results in a dereference of a fixed address"; - break; - }; + } // Generate an error node. ExplodedNode *N = C.generateErrorNode(State); if (!N) return; - SmallString<100> buf; - llvm::raw_svector_ostream os(buf); + SmallString<100> Buf; + llvm::raw_svector_ostream Out(Buf); SmallVector<SourceRange, 2> Ranges; switch (S->getStmtClass()) { case Stmt::ArraySubscriptExprClass: { - os << "Array access"; + Out << "Array access"; const ArraySubscriptExpr *AE = cast<ArraySubscriptExpr>(S); - AddDerefSource(os, Ranges, AE->getBase()->IgnoreParenCasts(), - State.get(), N->getLocationContext()); - os << DerefStr1; + AddDerefSource(Out, Ranges, AE->getBase()->IgnoreParenCasts(), State.get(), + N->getLocationContext()); + Out << " results in " << BT.getArrayMsg(); break; } case Stmt::ArraySectionExprClass: { - os << "Array access"; + Out << "Array access"; const ArraySectionExpr *AE = cast<ArraySectionExpr>(S); - AddDerefSource(os, Ranges, AE->getBase()->IgnoreParenCasts(), - State.get(), N->getLocationContext()); - os << DerefStr1; + AddDerefSource(Out, Ranges, AE->getBase()->IgnoreParenCasts(), State.get(), + N->getLocationContext()); + Out << " results in " << BT.getArrayMsg(); break; } case Stmt::UnaryOperatorClass: { - os << BT->getDescription(); + Out << BT.getDescription(); const UnaryOperator *U = cast<UnaryOperator>(S); - AddDerefSource(os, Ranges, U->getSubExpr()->IgnoreParens(), - State.get(), N->getLocationContext(), true); + AddDerefSource(Out, Ranges, U->getSubExpr()->IgnoreParens(), State.get(), + N->getLocationContext(), true); break; } case Stmt::MemberExprClass: { const MemberExpr *M = cast<MemberExpr>(S); if (M->isArrow() || isDeclRefExprToReference(M->getBase())) { - os << "Access to field '" << M->getMemberNameInfo() << "'" << DerefStr2; - AddDerefSource(os, Ranges, M->getBase()->IgnoreParenCasts(), - State.get(), N->getLocationContext(), true); + Out << "Access to field '" << M->getMemberNameInfo() << "' results in " + << BT.getFieldMsg(); + AddDerefSource(Out, Ranges, M->getBase()->IgnoreParenCasts(), State.get(), + N->getLocationContext(), true); } break; } case Stmt::ObjCIvarRefExprClass: { const ObjCIvarRefExpr *IV = cast<ObjCIvarRefExpr>(S); - os << "Access to instance variable '" << *IV->getDecl() << "'" << DerefStr2; - AddDerefSource(os, Ranges, IV->getBase()->IgnoreParenCasts(), - State.get(), N->getLocationContext(), true); + Out << "Access to instance variable '" << *IV->getDecl() << "' results in " + << BT.getFieldMsg(); + AddDerefSource(Out, Ranges, IV->getBase()->IgnoreParenCasts(), State.get(), + N->getLocationContext(), true); break; } default: break; } - auto report = std::make_unique<PathSensitiveBugReport>( - *BT, buf.empty() ? BT->getDescription() : buf.str(), N); + auto BR = std::make_unique<PathSensitiveBugReport>( + BT, Buf.empty() ? BT.getDescription() : Buf.str(), N); - bugreporter::trackExpressionValue(N, bugreporter::getDerefExpr(S), *report); + bugreporter::trackExpressionValue(N, bugreporter::getDerefExpr(S), *BR); for (SmallVectorImpl<SourceRange>::iterator I = Ranges.begin(), E = Ranges.end(); I!=E; ++I) - report->addRange(*I); + BR->addRange(*I); - C.emitReport(std::move(report)); + C.emitReport(std::move(BR)); } void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S, @@ -275,7 +261,7 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S, if (l.isUndef()) { const Expr *DerefExpr = getDereferenceExpr(S); if (!suppressReport(C, DerefExpr)) - reportBug(DerefKind::UndefinedPointerValue, C.getState(), DerefExpr, C); + reportBug(UndefBug, C.getState(), DerefExpr, C); return; } @@ -296,7 +282,7 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S, // we call an "explicit" null dereference. const Expr *expr = getDereferenceExpr(S); if (!suppressReport(C, expr)) { - reportBug(DerefKind::NullPointer, nullState, expr, C); + reportBug(NullBug, nullState, expr, C); return; } } @@ -314,7 +300,7 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S, if (location.isConstant()) { const Expr *DerefExpr = getDereferenceExpr(S, isLoad); if (!suppressReport(C, DerefExpr)) - reportBug(DerefKind::FixedAddress, notNullState, DerefExpr, C); + reportBug(FixedAddressBug, notNullState, DerefExpr, C); return; } @@ -330,7 +316,7 @@ void DereferenceChecker::checkBind(SVal L, SVal V, const Stmt *S, // One should never write to label addresses. if (auto Label = L.getAs<loc::GotoLabel>()) { - reportBug(DerefKind::AddressOfLabel, C.getState(), S, C); + reportBug(LabelBug, C.getState(), S, C); return; } @@ -351,7 +337,7 @@ void DereferenceChecker::checkBind(SVal L, SVal V, const Stmt *S, if (!StNonNull) { const Expr *expr = getDereferenceExpr(S, /*IsBind=*/true); if (!suppressReport(C, expr)) { - reportBug(DerefKind::NullPointer, StNull, expr, C); + reportBug(NullBug, StNull, expr, C); return; } } @@ -369,7 +355,7 @@ void DereferenceChecker::checkBind(SVal L, SVal V, const Stmt *S, if (V.isConstant()) { const Expr *DerefExpr = getDereferenceExpr(S, true); if (!suppressReport(C, DerefExpr)) - reportBug(DerefKind::FixedAddress, State, DerefExpr, C); + reportBug(FixedAddressBug, State, DerefExpr, C); return; } @@ -392,26 +378,8 @@ void DereferenceChecker::checkBind(SVal L, SVal V, const Stmt *S, C.addTransition(State, this); } -void ento::registerDereferenceModeling(CheckerManager &Mgr) { - Mgr.registerChecker<DereferenceChecker>(); -} - -bool ento::shouldRegisterDereferenceModeling(const CheckerManager &) { - return true; -} - void ento::registerNullDereferenceChecker(CheckerManager &Mgr) { - auto *Chk = Mgr.getChecker<DereferenceChecker>(); - Chk->CheckNullDereference = true; - Chk->BT_Null.reset(new BugType(Mgr.getCurrentCheckerName(), - "Dereference of null pointer", - categories::LogicError)); - Chk->BT_Undef.reset(new BugType(Mgr.getCurrentCheckerName(), - "Dereference of undefined pointer value", - categories::LogicError)); - Chk->BT_Label.reset(new BugType(Mgr.getCurrentCheckerName(), - "Dereference of the address of a label", - categories::LogicError)); + Mgr.getChecker<DereferenceChecker>()->NullDerefChecker.enable(Mgr); } bool ento::shouldRegisterNullDereferenceChecker(const CheckerManager &) { @@ -419,11 +387,7 @@ bool ento::shouldRegisterNullDereferenceChecker(const CheckerManager &) { } void ento::registerFixedAddressDereferenceChecker(CheckerManager &Mgr) { - auto *Chk = Mgr.getChecker<DereferenceChecker>(); - Chk->CheckFixedDereference = true; - Chk->BT_FixedAddress.reset(new BugType(Mgr.getCurrentCheckerName(), - "Dereference of a fixed address", - categories::LogicError)); + Mgr.getChecker<DereferenceChecker>()->FixedDerefChecker.enable(Mgr); } bool ento::shouldRegisterFixedAddressDereferenceChecker( diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index a7704da..369d619 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -2693,7 +2693,7 @@ void MallocChecker::HandleUseAfterFree(CheckerContext &C, SourceRange Range, Frontend->UseFreeBug, AF.Kind == AF_InnerBuffer ? "Inner pointer of container used after re/deallocation" - : "Use of memory after it is freed", + : "Use of memory after it is released", N); R->markInteresting(Sym); @@ -2721,8 +2721,8 @@ void MallocChecker::HandleDoubleFree(CheckerContext &C, SourceRange Range, if (ExplodedNode *N = C.generateErrorNode()) { auto R = std::make_unique<PathSensitiveBugReport>( Frontend->DoubleFreeBug, - (Released ? "Attempt to free released memory" - : "Attempt to free non-owned memory"), + (Released ? "Attempt to release already released memory" + : "Attempt to release non-owned memory"), N); if (Range.isValid()) R->addRange(Range); diff --git a/clang/test/Analysis/Inputs/expected-plists/NewDelete-path-notes.cpp.plist b/clang/test/Analysis/Inputs/expected-plists/NewDelete-path-notes.cpp.plist index 957988b..e4adeca 100644 --- a/clang/test/Analysis/Inputs/expected-plists/NewDelete-path-notes.cpp.plist +++ b/clang/test/Analysis/Inputs/expected-plists/NewDelete-path-notes.cpp.plist @@ -33,9 +33,9 @@ </array> <key>depth</key><integer>0</integer> <key>extended_message</key> - <string>Attempt to free released memory</string> + <string>Attempt to release already released memory</string> <key>message</key> - <string>Attempt to free released memory</string> + <string>Attempt to release already released memory</string> </dict> <dict> <key>kind</key><string>control</string> @@ -232,7 +232,7 @@ </array> </dict> </array> - <key>description</key><string>Attempt to free released memory</string> + <key>description</key><string>Attempt to release already released memory</string> <key>category</key><string>Memory error</string> <key>type</key><string>Double free</string> <key>check_name</key><string>cplusplus.NewDelete</string> @@ -456,12 +456,12 @@ </array> <key>depth</key><integer>0</integer> <key>extended_message</key> - <string>Attempt to free released memory</string> + <string>Attempt to release already released memory</string> <key>message</key> - <string>Attempt to free released memory</string> + <string>Attempt to release already released memory</string> </dict> </array> - <key>description</key><string>Attempt to free released memory</string> + <key>description</key><string>Attempt to release already released memory</string> <key>category</key><string>Memory error</string> <key>type</key><string>Double free</string> <key>check_name</key><string>cplusplus.NewDelete</string> diff --git a/clang/test/Analysis/Inputs/expected-plists/malloc-plist.c.plist b/clang/test/Analysis/Inputs/expected-plists/malloc-plist.c.plist index 8ae5850..3fdf5da4 100644 --- a/clang/test/Analysis/Inputs/expected-plists/malloc-plist.c.plist +++ b/clang/test/Analysis/Inputs/expected-plists/malloc-plist.c.plist @@ -1725,12 +1725,12 @@ </array> <key>depth</key><integer>0</integer> <key>extended_message</key> - <string>Use of memory after it is freed</string> + <string>Use of memory after it is released</string> <key>message</key> - <string>Use of memory after it is freed</string> + <string>Use of memory after it is released</string> </dict> </array> - <key>description</key><string>Use of memory after it is freed</string> + <key>description</key><string>Use of memory after it is released</string> <key>category</key><string>Memory error</string> <key>type</key><string>Use-after-free</string> <key>check_name</key><string>unix.Malloc</string> @@ -2985,12 +2985,12 @@ </array> <key>depth</key><integer>0</integer> <key>extended_message</key> - <string>Use of memory after it is freed</string> + <string>Use of memory after it is released</string> <key>message</key> - <string>Use of memory after it is freed</string> + <string>Use of memory after it is released</string> </dict> </array> - <key>description</key><string>Use of memory after it is freed</string> + <key>description</key><string>Use of memory after it is released</string> <key>category</key><string>Memory error</string> <key>type</key><string>Use-after-free</string> <key>check_name</key><string>unix.Malloc</string> diff --git a/clang/test/Analysis/Inputs/overloaded-delete-in-header.h b/clang/test/Analysis/Inputs/overloaded-delete-in-header.h index 8243961..96aa4af 100644 --- a/clang/test/Analysis/Inputs/overloaded-delete-in-header.h +++ b/clang/test/Analysis/Inputs/overloaded-delete-in-header.h @@ -12,7 +12,7 @@ void DeleteInHeader::operator delete(void *ptr) { ::operator delete(ptr); - self->data = 2; // expected-warning {{Use of memory after it is freed [cplusplus.NewDelete]}} + self->data = 2; // expected-warning {{Use of memory after it is released [cplusplus.NewDelete]}} } #endif // OVERLOADED_DELETE_IN_SYSTEM_HEADER diff --git a/clang/test/Analysis/Malloc+MismatchedDeallocator+NewDelete.cpp b/clang/test/Analysis/Malloc+MismatchedDeallocator+NewDelete.cpp index 6c20b4b..b9eb85d 100644 --- a/clang/test/Analysis/Malloc+MismatchedDeallocator+NewDelete.cpp +++ b/clang/test/Analysis/Malloc+MismatchedDeallocator+NewDelete.cpp @@ -9,7 +9,7 @@ void testMallocDoubleFree() { int *p = (int *)malloc(sizeof(int)); free(p); - free(p); // expected-warning{{Attempt to free released memory}} + free(p); // expected-warning{{Attempt to release already released memory}} } void testMallocLeak() { @@ -19,7 +19,7 @@ void testMallocLeak() { void testMallocUseAfterFree() { int *p = (int *)malloc(sizeof(int)); free(p); - int j = *p; // expected-warning{{Use of memory after it is freed}} + int j = *p; // expected-warning{{Use of memory after it is released}} } void testMallocBadFree() { @@ -46,7 +46,7 @@ void testMismatchedDeallocator() { void testNewDoubleFree() { int *p = new int; delete p; - delete p; // expected-warning{{Attempt to free released memory}} + delete p; // expected-warning{{Attempt to release already released memory}} } void testNewLeak() { @@ -59,7 +59,7 @@ void testNewLeak() { void testNewUseAfterFree() { int *p = (int *)operator new(0); delete p; - int j = *p; // expected-warning{{Use of memory after it is freed}} + int j = *p; // expected-warning{{Use of memory after it is released}} } void testNewBadFree() { @@ -95,7 +95,7 @@ void testShouldReportDoubleFreeNotMismatched() { int *p = (int*)malloc(sizeof(int)*4); globalPtr = p; free(p); - delete globalPtr; // expected-warning {{Attempt to free released memory}} + delete globalPtr; // expected-warning {{Attempt to release already released memory}} } int *allocIntArray(unsigned c) { return new int[c]; diff --git a/clang/test/Analysis/NewDelete-checker-test.cpp b/clang/test/Analysis/NewDelete-checker-test.cpp index 7c3e142..c417b9c 100644 --- a/clang/test/Analysis/NewDelete-checker-test.cpp +++ b/clang/test/Analysis/NewDelete-checker-test.cpp @@ -155,52 +155,52 @@ void g(SomeClass &c, ...); void testUseFirstArgAfterDelete() { int *p = new int; delete p; - f(p); // newdelete-warning{{Use of memory after it is freed}} + f(p); // newdelete-warning{{Use of memory after it is released}} } void testUseMiddleArgAfterDelete(int *p) { delete p; - f(0, p); // newdelete-warning{{Use of memory after it is freed}} + f(0, p); // newdelete-warning{{Use of memory after it is released}} } void testUseLastArgAfterDelete(int *p) { delete p; - f(0, 0, p); // newdelete-warning{{Use of memory after it is freed}} + f(0, 0, p); // newdelete-warning{{Use of memory after it is released}} } void testUseSeveralArgsAfterDelete(int *p) { delete p; - f(p, p, p); // newdelete-warning{{Use of memory after it is freed}} + f(p, p, p); // newdelete-warning{{Use of memory after it is released}} } void testUseRefArgAfterDelete(SomeClass &c) { delete &c; - g(c); // newdelete-warning{{Use of memory after it is freed}} + g(c); // newdelete-warning{{Use of memory after it is released}} } void testVariadicArgAfterDelete() { SomeClass c; int *p = new int; delete p; - g(c, 0, p); // newdelete-warning{{Use of memory after it is freed}} + g(c, 0, p); // newdelete-warning{{Use of memory after it is released}} } void testUseMethodArgAfterDelete(int *p) { SomeClass *c = new SomeClass; delete p; - c->f(p); // newdelete-warning{{Use of memory after it is freed}} + c->f(p); // newdelete-warning{{Use of memory after it is released}} } void testUseThisAfterDelete() { SomeClass *c = new SomeClass; delete c; - c->f(0); // newdelete-warning{{Use of memory after it is freed}} + c->f(0); // newdelete-warning{{Use of memory after it is released}} } void testDoubleDelete() { int *p = new int; delete p; - delete p; // newdelete-warning{{Attempt to free released memory}} + delete p; // newdelete-warning{{Attempt to release already released memory}} } void testExprDeleteArg() { @@ -412,7 +412,7 @@ public: void testDoubleDeleteClassInstance() { DerefClass *foo = new DerefClass(); delete foo; - delete foo; // newdelete-warning {{Attempt to free released memory}} + delete foo; // newdelete-warning {{Attempt to release already released memory}} } class EmptyClass{ @@ -424,7 +424,7 @@ public: void testDoubleDeleteEmptyClass() { EmptyClass *foo = new EmptyClass(); delete foo; - delete foo; // newdelete-warning {{Attempt to free released memory}} + delete foo; // newdelete-warning {{Attempt to release already released memory}} } struct Base { diff --git a/clang/test/Analysis/NewDelete-intersections.mm b/clang/test/Analysis/NewDelete-intersections.mm index e897f48..eddfb32 100644 --- a/clang/test/Analysis/NewDelete-intersections.mm +++ b/clang/test/Analysis/NewDelete-intersections.mm @@ -78,11 +78,11 @@ void testObjcFreeNewed() { void testFreeAfterDelete() { int *p = new int; delete p; - free(p); // newdelete-warning{{Use of memory after it is freed}} + free(p); // newdelete-warning{{Use of memory after it is released}} } void testStandardPlacementNewAfterDelete() { int *p = new int; delete p; - p = new (p) int; // newdelete-warning{{Use of memory after it is freed}} + p = new (p) int; // newdelete-warning{{Use of memory after it is released}} } diff --git a/clang/test/Analysis/NewDelete-path-notes.cpp b/clang/test/Analysis/NewDelete-path-notes.cpp index 2837fd1..852632f 100644 --- a/clang/test/Analysis/NewDelete-path-notes.cpp +++ b/clang/test/Analysis/NewDelete-path-notes.cpp @@ -16,8 +16,8 @@ void test() { delete p; // expected-note@-1 {{Memory is released}} - delete p; // expected-warning {{Attempt to free released memory}} - // expected-note@-1 {{Attempt to free released memory}} + delete p; // expected-warning {{Attempt to release already released memory}} + // expected-note@-1 {{Attempt to release already released memory}} } struct Odd { @@ -29,7 +29,7 @@ struct Odd { void test(Odd *odd) { odd->kill(); // expected-note{{Calling 'Odd::kill'}} // expected-note@-1 {{Returning; memory was released}} - delete odd; // expected-warning {{Attempt to free released memory}} - // expected-note@-1 {{Attempt to free released memory}} + delete odd; // expected-warning {{Attempt to release already released memory}} + // expected-note@-1 {{Attempt to release already released memory}} } diff --git a/clang/test/Analysis/analyzer-enabled-checkers.c b/clang/test/Analysis/analyzer-enabled-checkers.c index 78ee00de..a632b70 100644 --- a/clang/test/Analysis/analyzer-enabled-checkers.c +++ b/clang/test/Analysis/analyzer-enabled-checkers.c @@ -14,7 +14,6 @@ // CHECK-NEXT: core.BitwiseShift // CHECK-NEXT: core.CallAndMessageModeling // CHECK-NEXT: core.CallAndMessage -// CHECK-NEXT: core.DereferenceModeling // CHECK-NEXT: core.DivideZero // CHECK-NEXT: core.DynamicTypePropagation // CHECK-NEXT: core.FixedAddressDereference diff --git a/clang/test/Analysis/diagnostics/dtors.cpp b/clang/test/Analysis/diagnostics/dtors.cpp index 6a8349d..61e71fd 100644 --- a/clang/test/Analysis/diagnostics/dtors.cpp +++ b/clang/test/Analysis/diagnostics/dtors.cpp @@ -19,8 +19,8 @@ struct smart_ptr { return (x || 0) ? nullptr : s; // expected-note{{Field 'x' is 0}} // expected-note@-1{{Left side of '||' is false}} // expected-note@-2{{'?' condition is false}} - // expected-warning@-3{{Use of memory after it is freed}} - // expected-note@-4{{Use of memory after it is freed}} + // expected-warning@-3{{Use of memory after it is released}} + // expected-note@-4{{Use of memory after it is released}} } }; diff --git a/clang/test/Analysis/dtor.cpp b/clang/test/Analysis/dtor.cpp index c17c886..9e00e93 100644 --- a/clang/test/Analysis/dtor.cpp +++ b/clang/test/Analysis/dtor.cpp @@ -35,7 +35,7 @@ void testSmartPointer() { SmartPointer Deleter(mem); // destructor called here } - *mem = 0; // expected-warning{{Use of memory after it is freed}} + *mem = 0; // expected-warning{{Use of memory after it is released}} } @@ -48,7 +48,7 @@ void testSmartPointer2() { doSomething(); // destructor called here } - *mem = 0; // expected-warning{{Use of memory after it is freed}} + *mem = 0; // expected-warning{{Use of memory after it is released}} } @@ -65,7 +65,7 @@ void testSubclassSmartPointer() { doSomething(); // destructor called here } - *mem = 0; // expected-warning{{Use of memory after it is freed}} + *mem = 0; // expected-warning{{Use of memory after it is released}} } @@ -82,7 +82,7 @@ void testMultipleInheritance1() { doSomething(); // destructor called here } - *mem = 0; // expected-warning{{Use of memory after it is freed}} + *mem = 0; // expected-warning{{Use of memory after it is released}} } void testMultipleInheritance2() { @@ -93,7 +93,7 @@ void testMultipleInheritance2() { doSomething(); // destructor called here } - *mem = 0; // expected-warning{{Use of memory after it is freed}} + *mem = 0; // expected-warning{{Use of memory after it is released}} } void testMultipleInheritance3() { @@ -103,7 +103,7 @@ void testMultipleInheritance3() { // Remove dead bindings... doSomething(); // destructor called here - // expected-warning@28 {{Attempt to free released memory}} + // expected-warning@28 {{Attempt to release already released memory}} } } @@ -122,7 +122,7 @@ void testSmartPointerMember() { doSomething(); // destructor called here } - *mem = 0; // expected-warning{{Use of memory after it is freed}} + *mem = 0; // expected-warning{{Use of memory after it is release}} } @@ -524,7 +524,7 @@ struct NonTrivial { return *this; } ~NonTrivial() { - delete[] p; // expected-warning {{free released memory}} + delete[] p; // expected-warning {{release already released memory}} } }; @@ -593,5 +593,5 @@ void overrideLeak() { void overrideDoubleDelete() { auto *a = new CustomOperators(); delete a; - delete a; // expected-warning@577 {{Attempt to free released memory}} + delete a; // expected-warning@577 {{Attempt to release already released memory}} } diff --git a/clang/test/Analysis/getline-alloc.c b/clang/test/Analysis/getline-alloc.c index 74a40a1..43d0a2d 100644 --- a/clang/test/Analysis/getline-alloc.c +++ b/clang/test/Analysis/getline-alloc.c @@ -29,7 +29,7 @@ void test_getline_malloc_buffer() { ssize_t r = getdelim(&buffer, &n, '\r', F1); // ptr may be dangling - free(ptr); // expected-warning {{Attempt to free released memory}} + free(ptr); // expected-warning {{Attempt to release already released memory}} free(buffer); // ok fclose(F1); } diff --git a/clang/test/Analysis/gmalloc.c b/clang/test/Analysis/gmalloc.c index dae28eb..a94e5db 100644 --- a/clang/test/Analysis/gmalloc.c +++ b/clang/test/Analysis/gmalloc.c @@ -41,7 +41,7 @@ void f1(void) { g_free(g1); g_free(g2); - g_free(g2); // expected-warning{{Attempt to free released memory}} + g_free(g2); // expected-warning{{Attempt to release already released memory}} } void f2(void) { @@ -61,7 +61,7 @@ void f2(void) { g_free(g1); g_free(g2); g_free(g3); - g3 = g_memdup(g3, n_bytes); // expected-warning{{Use of memory after it is freed}} + g3 = g_memdup(g3, n_bytes); // expected-warning{{Use of memory after it is released}} } void f3(void) { diff --git a/clang/test/Analysis/malloc-annotations.c b/clang/test/Analysis/malloc-annotations.c index 3a8b1b2..68ac71d 100644 --- a/clang/test/Analysis/malloc-annotations.c +++ b/clang/test/Analysis/malloc-annotations.c @@ -45,13 +45,13 @@ void f1(void) { void f2(void) { int *p = malloc(12); free(p); - free(p); // expected-warning{{Attempt to free released memory}} + free(p); // expected-warning{{Attempt to release already released memory}} } void f2_realloc_0(void) { int *p = malloc(12); realloc(p,0); - realloc(p,0); // expected-warning{{Attempt to free released memory}} + realloc(p,0); // expected-warning{{Attempt to release already released memory}} } void f2_realloc_1(void) { @@ -106,25 +106,25 @@ void af1_g(struct stuff **pps) { void af2(void) { int *p = my_malloc(12); my_free(p); - free(p); // expected-warning{{Attempt to free released memory}} + free(p); // expected-warning{{Attempt to release already released memory}} } void af2b(void) { int *p = my_malloc(12); free(p); - my_free(p); // expected-warning{{Attempt to free released memory}} + my_free(p); // expected-warning{{Attempt to release already released memory}} } void af2c(void) { int *p = my_malloc(12); free(p); - my_hold(p); // expected-warning{{Attempt to free released memory}} + my_hold(p); // expected-warning{{Attempt to release already released memory}} } void af2d(void) { int *p = my_malloc(12); free(p); - my_hold2(0, 0, p); // expected-warning{{Attempt to free released memory}} + my_hold2(0, 0, p); // expected-warning{{Attempt to release already released memory}} } // No leak if malloc returns null. @@ -139,13 +139,13 @@ void af2e(void) { void af3(void) { int *p = my_malloc(12); my_hold(p); - free(p); // expected-warning{{Attempt to free non-owned memory}} + free(p); // expected-warning{{Attempt to release non-owned memory}} } int * af4(void) { int *p = my_malloc(12); my_free(p); - return p; // expected-warning{{Use of memory after it is freed}} + return p; // expected-warning{{Use of memory after it is released}} } // This case is (possibly) ok, be conservative @@ -211,13 +211,13 @@ void pr6293(void) { void f7(void) { char *x = (char*) malloc(4); free(x); - x[0] = 'a'; // expected-warning{{Use of memory after it is freed}} + x[0] = 'a'; // expected-warning{{Use of memory after it is released}} } void f7_realloc(void) { char *x = (char*) malloc(4); realloc(x,0); - x[0] = 'a'; // expected-warning{{Use of memory after it is freed}} + x[0] = 'a'; // expected-warning{{Use of memory after it is released}} } void PR6123(void) { diff --git a/clang/test/Analysis/malloc-annotations.cpp b/clang/test/Analysis/malloc-annotations.cpp index d75683f..67a069d 100644 --- a/clang/test/Analysis/malloc-annotations.cpp +++ b/clang/test/Analysis/malloc-annotations.cpp @@ -54,19 +54,19 @@ void af1_g(MemoryAllocator &Alloc, struct stuff **pps) { void af2(MemoryAllocator &Alloc) { void *p = Alloc.my_malloc(12); Alloc.my_free(p); - free(p); // expected-warning{{Attempt to free released memory}} + free(p); // expected-warning{{Attempt to release already released memory}} } void af2b(MemoryAllocator &Alloc) { void *p = Alloc.my_malloc(12); free(p); - Alloc.my_free(p); // expected-warning{{Attempt to free released memory}} + Alloc.my_free(p); // expected-warning{{Attempt to release already released memory}} } void af2c(MemoryAllocator &Alloc) { void *p = Alloc.my_malloc(12); free(p); - Alloc.my_hold(p); // expected-warning{{Attempt to free released memory}} + Alloc.my_hold(p); // expected-warning{{Attempt to release already released memory}} } // No leak if malloc returns null. @@ -81,13 +81,13 @@ void af2e(MemoryAllocator &Alloc) { void af3(MemoryAllocator &Alloc) { void *p = Alloc.my_malloc(12); Alloc.my_hold(p); - free(p); // expected-warning{{Attempt to free non-owned memory}} + free(p); // expected-warning{{Attempt to release non-owned memory}} } void * af4(MemoryAllocator &Alloc) { void *p = Alloc.my_malloc(12); Alloc.my_free(p); - return p; // expected-warning{{Use of memory after it is freed}} + return p; // expected-warning{{Use of memory after it is released}} } // This case is (possibly) ok, be conservative diff --git a/clang/test/Analysis/malloc-free-after-return.cpp b/clang/test/Analysis/malloc-free-after-return.cpp index cebd79a..5174e30 100644 --- a/clang/test/Analysis/malloc-free-after-return.cpp +++ b/clang/test/Analysis/malloc-free-after-return.cpp @@ -12,10 +12,10 @@ private: }; int *freeAfterReturnTemp() { - return S().getData(); // expected-warning {{Use of memory after it is freed}} + return S().getData(); // expected-warning {{Use of memory after it is released}} } int *freeAfterReturnLocal() { S X; - return X.getData(); // expected-warning {{Use of memory after it is freed}} + return X.getData(); // expected-warning {{Use of memory after it is released}} } diff --git a/clang/test/Analysis/malloc-interprocedural.c b/clang/test/Analysis/malloc-interprocedural.c index 5e5232a..e1569cf 100644 --- a/clang/test/Analysis/malloc-interprocedural.c +++ b/clang/test/Analysis/malloc-interprocedural.c @@ -59,13 +59,13 @@ int test4(void) { my_free1(data); data = (int *)my_malloc2(1, 4); my_free1(data); - return *data; // expected-warning {{Use of memory after it is freed}} + return *data; // expected-warning {{Use of memory after it is released}} } void test6(void) { int *data = (int *)my_malloc2(1, 4); my_free1((int*)data); - my_free1((int*)data); // expected-warning{{Use of memory after it is freed}} + my_free1((int*)data); // expected-warning{{Use of memory after it is released}} } // TODO: We should warn here. @@ -96,5 +96,5 @@ int uafAndCallsFooWithEmptyReturn(void) { int *x = (int*)malloc(12); free(x); fooWithEmptyReturn(12); - return *x; // expected-warning {{Use of memory after it is freed}} + return *x; // expected-warning {{Use of memory after it is released}} } diff --git a/clang/test/Analysis/malloc-plist.c b/clang/test/Analysis/malloc-plist.c index 6a3ba5b..caceaaf6 100644 --- a/clang/test/Analysis/malloc-plist.c +++ b/clang/test/Analysis/malloc-plist.c @@ -46,7 +46,7 @@ void test_wrapper(void) { (void) buf; }//expected-warning{{Potential leak}} -// Test what happens when the same call frees and allocated memory. +// Test what happens when the same call releases and allocated memory. // Also tests the stack hint for parameters, when they are passed directly or via pointer. void my_free(void *x) { free(x); @@ -60,7 +60,7 @@ void my_malloc_and_free(void **x) { void *test_double_action_call(void) { void *buf; my_malloc_and_free(&buf); - return buf; //expected-warning{{Use of memory after it is freed}} + return buf; //expected-warning{{Use of memory after it is released}} } // Test stack hint for 'reallocation failed'. @@ -98,7 +98,7 @@ void call_myfree_takingblock(void) { int *p = malloc(sizeof(int)); myfree_takingblock(some_block, p); - *p = 3;//expected-warning{{Use of memory after it is freed}} + *p = 3;//expected-warning{{Use of memory after it is released}} } // Test that we refer to the last symbol used in the leak diagnostic. diff --git a/clang/test/Analysis/malloc-refcounted.c b/clang/test/Analysis/malloc-refcounted.c index bfbe91d..224b60f 100644 --- a/clang/test/Analysis/malloc-refcounted.c +++ b/clang/test/Analysis/malloc-refcounted.c @@ -69,12 +69,12 @@ void test_uaf(void) { struct SomeData *data = alloc_data(); put_data_uncond(data); - data->i += 1; // expected-warning{{Use of memory after it is freed}} + data->i += 1; // expected-warning{{Use of memory after it is released}} } void test_no_uaf_atomic_after(void) { struct SomeData *data = alloc_data(); put_data_unrelated_atomic(data); - data->i += 1; // expected-warning{{Use of memory after it is freed}} + data->i += 1; // expected-warning{{Use of memory after it is released}} } diff --git a/clang/test/Analysis/malloc.c b/clang/test/Analysis/malloc.c index a9828cf..82eb364 100644 --- a/clang/test/Analysis/malloc.c +++ b/clang/test/Analysis/malloc.c @@ -97,13 +97,13 @@ void f1(void) { void f2(void) { int *p = malloc(12); free(p); - free(p); // expected-warning{{Attempt to free released memory}} + free(p); // expected-warning{{Attempt to release already released memory}} } void f2_realloc_0(void) { int *p = malloc(12); realloc(p,0); - realloc(p,0); // expected-warning{{Attempt to free released memory}} + realloc(p,0); // expected-warning{{Attempt to release already released memory}} } void f2_realloc_1(void) { @@ -153,7 +153,7 @@ void reallocSizeZero1(void) { char *p = malloc(12); char *r = realloc(p, 0); if (!r) { - free(p); // expected-warning {{Attempt to free released memory}} + free(p); // expected-warning {{Attempt to release already released memory}} } else { free(r); } @@ -163,11 +163,11 @@ void reallocSizeZero2(void) { char *p = malloc(12); char *r = realloc(p, 0); if (!r) { - free(p); // expected-warning {{Attempt to free released memory}} + free(p); // expected-warning {{Attempt to release already released memory}} } else { free(r); } - free(p); // expected-warning {{Attempt to free released memory}} + free(p); // expected-warning {{Attempt to release already released memory}} } void reallocSizeZero3(void) { @@ -262,7 +262,7 @@ void reallocfRadar6337483_3(void) { char * tmp; tmp = (char*)reallocf(buf, 0x1000000); if (!tmp) { - free(buf); // expected-warning {{Attempt to free released memory}} + free(buf); // expected-warning {{Attempt to release already released memory}} return; } buf = tmp; @@ -480,19 +480,19 @@ void pr6293(void) { void f7(void) { char *x = (char*) malloc(4); free(x); - x[0] = 'a'; // expected-warning{{Use of memory after it is freed}} + x[0] = 'a'; // expected-warning{{Use of memory after it is released}} } void f8(void) { char *x = (char*) malloc(4); free(x); - char *y = strndup(x, 4); // expected-warning{{Use of memory after it is freed}} + char *y = strndup(x, 4); // expected-warning{{Use of memory after it is released}} } void f7_realloc(void) { char *x = (char*) malloc(4); realloc(x,0); - x[0] = 'a'; // expected-warning{{Use of memory after it is freed}} + x[0] = 'a'; // expected-warning{{Use of memory after it is released}} } void PR6123(void) { @@ -773,7 +773,7 @@ void nullFree(void) { void paramFree(int *p) { myfoo(p); free(p); // no warning - myfoo(p); // expected-warning {{Use of memory after it is freed}} + myfoo(p); // expected-warning {{Use of memory after it is released}} } void allocaFree(void) { @@ -813,14 +813,14 @@ void mallocEscapeFreeFree(void) { int *p = malloc(12); myfoo(p); free(p); - free(p); // expected-warning{{Attempt to free released memory}} + free(p); // expected-warning{{Attempt to release already released memory}} } void mallocEscapeFreeUse(void) { int *p = malloc(12); myfoo(p); free(p); - myfoo(p); // expected-warning{{Use of memory after it is freed}} + myfoo(p); // expected-warning{{Use of memory after it is released}} } int *myalloc(void); @@ -846,7 +846,7 @@ void mallocBindFreeUse(void) { int *x = malloc(12); int *y = x; free(y); - myfoo(x); // expected-warning{{Use of memory after it is freed}} + myfoo(x); // expected-warning{{Use of memory after it is released}} } void mallocEscapeMalloc(void) { @@ -871,13 +871,13 @@ void mallocFreeMalloc(void) { void mallocFreeUse_params(void) { int *p = malloc(12); free(p); - myfoo(p); //expected-warning{{Use of memory after it is freed}} + myfoo(p); //expected-warning{{Use of memory after it is released}} } void mallocFreeUse_params2(void) { int *p = malloc(12); free(p); - myfooint(*p); //expected-warning{{Use of memory after it is freed}} + myfooint(*p); //expected-warning{{Use of memory after it is released}} } void mallocFailedOrNot(void) { @@ -895,14 +895,14 @@ struct StructWithInt { int *mallocReturnFreed(void) { int *p = malloc(12); free(p); - return p; // expected-warning {{Use of memory after it is freed}} + return p; // expected-warning {{Use of memory after it is released}} } int useAfterFreeStruct(void) { struct StructWithInt *px= malloc(sizeof(struct StructWithInt)); px->g = 5; free(px); - return px->g; // expected-warning {{Use of memory after it is freed}} + return px->g; // expected-warning {{Use of memory after it is released}} } void nonSymbolAsFirstArg(int *pp, struct StructWithInt *p); @@ -935,7 +935,7 @@ void vallocEscapeFreeUse(void) { int *p = valloc(12); myfoo(p); free(p); - myfoo(p); // expected-warning{{Use of memory after it is freed}} + myfoo(p); // expected-warning{{Use of memory after it is released}} } int *Gl; @@ -1543,7 +1543,7 @@ void freeButNoMalloc(int *p, int x){ free(p); //user forgot a return here. } - free(p); // expected-warning {{Attempt to free released memory}} + free(p); // expected-warning {{Attempt to release already released memory}} } struct HasPtr { @@ -1553,7 +1553,7 @@ struct HasPtr { char* reallocButNoMalloc(struct HasPtr *a, int c, int size) { int *s; char *b = realloc(a->p, size); - char *m = realloc(a->p, size); // expected-warning {{Attempt to free released memory}} + char *m = realloc(a->p, size); // expected-warning {{Attempt to release already released memory}} // We don't expect a use-after-free for a->P here because the warning above // is a sink. return a->p; // no-warning @@ -1722,7 +1722,7 @@ void testOffsetZeroDoubleFree(void) { int *array = malloc(sizeof(int)*2); int *p = &array[0]; free(p); - free(&array[0]); // expected-warning{{Attempt to free released memory}} + free(&array[0]); // expected-warning{{Attempt to release already released memory}} } void testOffsetPassedToStrlen(void) { @@ -1835,7 +1835,7 @@ int testNoCheckerDataPropagationFromLogicalOpOperandToOpResult(void) { int ok = (param && value); free(param); free(value); - // Previously we ended up with 'Use of memory after it is freed' on return. + // Previously we ended up with 'Use of memory after it is released' on return. return ok; // no warning } @@ -1970,7 +1970,7 @@ void gh149754(void *p) { // was since then removed for the codebase. if (!realloc(p, 8)) { realloc(p, 8); - free(p); // expected-warning {{Attempt to free released memory}} + free(p); // expected-warning {{Attempt to release already released memory}} } // expected-warning@+1 {{Potential memory leak}} } diff --git a/clang/test/Analysis/malloc.mm b/clang/test/Analysis/malloc.mm index 5b816a1..8b4de9a 100644 --- a/clang/test/Analysis/malloc.mm +++ b/clang/test/Analysis/malloc.mm @@ -35,7 +35,7 @@ void testNSStringFreeWhenDoneYES3(NSUInteger dataLength) { void testNSStringFreeWhenDoneYES4(NSUInteger dataLength) { unichar *data = (unichar*)malloc(42); NSString *nsstr = [[NSString alloc] initWithCharactersNoCopy:data length:dataLength freeWhenDone:1]; - free(data); //expected-warning {{Attempt to free non-owned memory}} + free(data); //expected-warning {{Attempt to release non-owned memory}} } void testNSStringFreeWhenDoneYES(NSUInteger dataLength) { @@ -95,14 +95,14 @@ void testOffsetFree() { void testRelinquished1() { void *data = malloc(42); NSData *nsdata = [NSData dataWithBytesNoCopy:data length:42 freeWhenDone:1]; - free(data); // expected-warning {{Attempt to free non-owned memory}} + free(data); // expected-warning {{Attempt to release non-owned memory}} } void testRelinquished2() { void *data = malloc(42); NSData *nsdata; free(data); - [NSData dataWithBytesNoCopy:data length:42]; // expected-warning {{Use of memory after it is freed}} + [NSData dataWithBytesNoCopy:data length:42]; // expected-warning {{Use of memory after it is released}} } @interface My @@ -112,7 +112,7 @@ void testRelinquished2() { void testUseAfterFree() { int *p = (int *)malloc(sizeof(int)); free(p); - [My param:p]; // expected-warning{{Use of memory after it is freed}} + [My param:p]; // expected-warning{{Use of memory after it is released}} } void testNoCopy() { @@ -318,7 +318,7 @@ NSString *test12365078_no_malloc_returnValue(unichar *characters) { void test12365078_nocheck_nomalloc(unichar *characters) { NSString *string = [[NSString alloc] initWithCharactersNoCopy:characters length:12 freeWhenDone:1]; - free(characters); // expected-warning {{Attempt to free non-owned memory}} + free(characters); // expected-warning {{Attempt to release non-owned memory}} } void test12365078_nested(unichar *characters) { @@ -339,7 +339,7 @@ void test12365078_nested(unichar *characters) { void test12365078_check_positive() { unichar *characters = (unichar*)malloc(12); NSString *string = [[NSString alloc] initWithCharactersNoCopy:characters length:12 freeWhenDone:1]; - if (string) free(characters); // expected-warning{{Attempt to free non-owned memory}} + if (string) free(characters); // expected-warning{{Attempt to release non-owned memory}} } void *test_reinterpret_cast_to_block() { diff --git a/clang/test/Analysis/new.cpp b/clang/test/Analysis/new.cpp index 15c27e7..8e5c6c4 100644 --- a/clang/test/Analysis/new.cpp +++ b/clang/test/Analysis/new.cpp @@ -112,7 +112,7 @@ void testCacheOut(PtrWrapper w) { void testUseAfter(int *p) { SomeClass *c = new SomeClass; free(p); - c->f(p); // expected-warning{{Use of memory after it is freed}} + c->f(p); // expected-warning{{Use of memory after it is released}} delete c; } @@ -140,25 +140,25 @@ void testDeleteMallocked() { void testDeleteOpAfterFree() { int *p = (int *)malloc(sizeof(int)); free(p); - operator delete(p); // expected-warning{{Use of memory after it is freed}} + operator delete(p); // expected-warning{{Use of memory after it is released}} } void testDeleteAfterFree() { int *p = (int *)malloc(sizeof(int)); free(p); - delete p; // expected-warning{{Use of memory after it is freed}} + delete p; // expected-warning{{Use of memory after it is released}} } void testStandardPlacementNewAfterFree() { int *p = (int *)malloc(sizeof(int)); free(p); - p = new(p) int; // expected-warning{{Use of memory after it is freed}} + p = new(p) int; // expected-warning{{Use of memory after it is released}} } void testCustomPlacementNewAfterFree() { int *p = (int *)malloc(sizeof(int)); free(p); - p = new(0, p) int; // expected-warning{{Use of memory after it is freed}} + p = new(0, p) int; // expected-warning{{Use of memory after it is released}} } void testUsingThisAfterDelete() { diff --git a/clang/test/Analysis/retain-count-alloc.cpp b/clang/test/Analysis/retain-count-alloc.cpp index 472cbbf..4b023a7 100644 --- a/clang/test/Analysis/retain-count-alloc.cpp +++ b/clang/test/Analysis/retain-count-alloc.cpp @@ -33,5 +33,5 @@ void useAfterFree(__isl_take Object *A) { freeObj(B); A->Ref = 13; - // no-warning: 'Use of memory after it is freed' was here. + // no-warning: 'Use of memory after it is released' was here. } diff --git a/clang/test/Analysis/self-assign.cpp b/clang/test/Analysis/self-assign.cpp index 7d3ea99b..d5c75c4 100644 --- a/clang/test/Analysis/self-assign.cpp +++ b/clang/test/Analysis/self-assign.cpp @@ -42,8 +42,8 @@ StringUsed &StringUsed::operator=(const StringUsed &rhs) { // expected-note@-2{{TRUE}} // expected-note@-3{{UNKNOWN}} free(str); // expected-note{{Memory is released}} - str = strdup(rhs.str); // expected-warning{{Use of memory after it is freed}} - // expected-note@-1{{Use of memory after it is freed}} + str = strdup(rhs.str); // expected-warning{{Use of memory after it is released}} + // expected-note@-1{{Use of memory after it is released}} // expected-note@-2{{Memory is allocated}} return *this; } @@ -90,8 +90,8 @@ StringUnused &StringUnused::operator=(const StringUnused &rhs) { // expected-note@-2{{TRUE}} // expected-note@-3{{UNKNOWN}} free(str); // expected-note{{Memory is released}} - str = strdup(rhs.str); // expected-warning{{Use of memory after it is freed}} - // expected-note@-1{{Use of memory after it is freed}} + str = strdup(rhs.str); // expected-warning{{Use of memory after it is released}} + // expected-note@-1{{Use of memory after it is released}} return *this; } diff --git a/clang/test/Analysis/stack-frame-context-revision.cpp b/clang/test/Analysis/stack-frame-context-revision.cpp index 51f86de..bd2f046 100644 --- a/clang/test/Analysis/stack-frame-context-revision.cpp +++ b/clang/test/Analysis/stack-frame-context-revision.cpp @@ -31,7 +31,7 @@ void test(Node *N) { delete N; N = Next.getPointer(); - // no-warning: 'Use of memory after it is freed' was here as the same + // no-warning: 'Use of memory after it is released' was here as the same // 'StackArgumentsSpaceRegion' purged out twice as 'P'. } } diff --git a/clang/test/Analysis/std-c-library-functions-arg-enabled-checkers.c b/clang/test/Analysis/std-c-library-functions-arg-enabled-checkers.c index 7f9c9ff..b388c31 100644 --- a/clang/test/Analysis/std-c-library-functions-arg-enabled-checkers.c +++ b/clang/test/Analysis/std-c-library-functions-arg-enabled-checkers.c @@ -22,7 +22,6 @@ // CHECK-NEXT: core.BitwiseShift // CHECK-NEXT: core.CallAndMessageModeling // CHECK-NEXT: core.CallAndMessage -// CHECK-NEXT: core.DereferenceModeling // CHECK-NEXT: core.DivideZero // CHECK-NEXT: core.DynamicTypePropagation // CHECK-NEXT: core.FixedAddressDereference diff --git a/clang/test/Analysis/std-string.cpp b/clang/test/Analysis/std-string.cpp index ee6dc02..150f557 100644 --- a/clang/test/Analysis/std-string.cpp +++ b/clang/test/Analysis/std-string.cpp @@ -57,8 +57,8 @@ void ctor_notetag_on_constraining_symbol(const char *p) { free((void *)p); // expected-note {{Memory is released}} free((void *)p); - // expected-warning@-1 {{Attempt to free released memory}} - // expected-note@-2 {{Attempt to free released memory}} + // expected-warning@-1 {{Attempt to release already released memory}} + // expected-note@-2 {{Attempt to release already released memory}} } void ctor_no_notetag_symbol_already_constrained(const char *p) { @@ -73,8 +73,8 @@ void ctor_no_notetag_symbol_already_constrained(const char *p) { free((void *)p); // expected-note {{Memory is released}} free((void *)p); - // expected-warning@-1 {{Attempt to free released memory}} - // expected-note@-2 {{Attempt to free released memory}} + // expected-warning@-1 {{Attempt to release already released memory}} + // expected-note@-2 {{Attempt to release already released memory}} } void ctor_no_notetag_if_not_interesting(const char *p1, const char *p2) { @@ -83,6 +83,6 @@ void ctor_no_notetag_if_not_interesting(const char *p1, const char *p2) { free((void *)p1); // expected-note {{Memory is released}} free((void *)p1); - // expected-warning@-1 {{Attempt to free released memory}} - // expected-note@-2 {{Attempt to free released memory}} + // expected-warning@-1 {{Attempt to release already released memory}} + // expected-note@-2 {{Attempt to release already released memory}} } diff --git a/clang/test/CIR/CodeGen/complex-cast.cpp b/clang/test/CIR/CodeGen/complex-cast.cpp index 0881057..a8f51cd 100644 --- a/clang/test/CIR/CodeGen/complex-cast.cpp +++ b/clang/test/CIR/CodeGen/complex-cast.cpp @@ -336,7 +336,6 @@ void lvalue_to_rvalue_bitcast() { double _Complex b = __builtin_bit_cast(double _Complex, a); } - // CIR-BEFORE: %{{.*}} = cir.cast(bitcast, %{{.*}} : !cir.ptr<!rec_CX>), !cir.ptr<!cir.complex<!cir.double>> // CIR-AFTER: %{{.*}} = cir.cast(bitcast, %{{.*}} : !cir.ptr<!rec_CX>), !cir.ptr<!cir.complex<!cir.double>> @@ -356,3 +355,21 @@ void lvalue_to_rvalue_bitcast() { // OGCG: %[[B_IMAG_PTR:.*]] = getelementptr inbounds nuw { double, double }, ptr %[[B_ADDR]], i32 0, i32 1 // OGCG: store double %[[A_REAL]], ptr %[[B_REAL_PTR]], align 8 // OGCG: store double %[[A_IMAG]], ptr %[[B_IMAG_PTR]], align 8 + +void lvalue_bitcast() { + CX a; + (double _Complex &)a = {}; +} + +// CIR-BEFORE: %{{.*}} = cir.cast(bitcast, %{{.*}} : !cir.ptr<!rec_CX>), !cir.ptr<!cir.complex<!cir.double>> + +// CIR-AFTER: %{{.*}} = cir.cast(bitcast, %{{.*}} : !cir.ptr<!rec_CX>), !cir.ptr<!cir.complex<!cir.double>> + +// LLVM: %[[A_ADDR:.*]] = alloca %struct.CX, i64 1, align 8 +// LLVM: store { double, double } zeroinitializer, ptr %[[A_ADDR]], align 8 + +// OGCG: %[[A_ADDR]] = alloca %struct.CX, align 8 +// OGCG: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { double, double }, ptr %[[A_ADDR]], i32 0, i32 0 +// OGCG: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { double, double }, ptr %[[A_ADDR]], i32 0, i32 1 +// OGCG: store double 0.000000e+00, ptr %[[A_REAL_PTR]], align 8 +// OGCG: store double 0.000000e+00, ptr %[[A_IMAG_PTR]], align 8 diff --git a/clang/test/CIR/Lowering/poison.cir b/clang/test/CIR/Lowering/poison.cir new file mode 100644 index 0000000..6f8b792 --- /dev/null +++ b/clang/test/CIR/Lowering/poison.cir @@ -0,0 +1,14 @@ +// RUN: cir-translate -cir-to-llvmir --disable-cc-lowering -o %t.ll %s +// RUN: FileCheck -check-prefix=LLVM --input-file=%t.ll %s + +!s32i = !cir.int<s, 32> + +module { + cir.func @lower_poison() -> !s32i { + %0 = cir.const #cir.poison : !s32i + cir.return %0 : !s32i + } + // LLVM-LABEL: @lower_poison + // LLVM-NEXT: ret i32 poison + // LLVM-NEXT: } +} diff --git a/clang/test/CIR/Transforms/bit.cir b/clang/test/CIR/Transforms/bit.cir index c85b05d..fc27adb 100644 --- a/clang/test/CIR/Transforms/bit.cir +++ b/clang/test/CIR/Transforms/bit.cir @@ -25,6 +25,26 @@ module { // CHECK-NEXT: cir.return %[[R]] : !u32i // CHECK-NEXT: } + cir.func @fold_clz_zero_poison() -> !u32i { + %0 = cir.const #cir.int<0> : !u32i + %1 = cir.clz %0 poison_zero : !u32i + cir.return %1 : !u32i + } + // CHECK-LABEL: @fold_clz_zero_poison + // CHECK-NEXT: %[[R:.+]] = cir.const #cir.poison : !u32i + // CHECK-NEXT: cir.return %[[R]] : !u32i + // CHECK-NEXT: } + + cir.func @fold_clz_zero_no_poison() -> !u32i { + %0 = cir.const #cir.int<0> : !u32i + %1 = cir.clz %0 : !u32i + cir.return %1 : !u32i + } + // CHECK-LABEL: @fold_clz_zero_no_poison + // CHECK-NEXT: %[[R:.+]] = cir.const #cir.int<32> : !u32i + // CHECK-NEXT: cir.return %[[R]] : !u32i + // CHECK-NEXT: } + cir.func @fold_ctz() -> !u32i { %0 = cir.const #cir.int<2> : !u32i %1 = cir.ctz %0 : !u32i @@ -35,6 +55,26 @@ module { // CHECK-NEXT: cir.return %[[R]] : !u32i // CHECK-NEXT: } + cir.func @fold_ctz_zero_poison() -> !u32i { + %0 = cir.const #cir.int<0> : !u32i + %1 = cir.ctz %0 poison_zero : !u32i + cir.return %1 : !u32i + } + // CHECK-LABEL: @fold_ctz_zero_poison + // CHECK-NEXT: %[[R:.+]] = cir.const #cir.poison : !u32i + // CHECK-NEXT: cir.return %[[R]] : !u32i + // CHECK-NEXT: } + + cir.func @fold_ctz_zero_no_poison() -> !u32i { + %0 = cir.const #cir.int<0> : !u32i + %1 = cir.ctz %0 : !u32i + cir.return %1 : !u32i + } + // CHECK-LABEL: @fold_ctz_zero_no_poison + // CHECK-NEXT: %[[R:.+]] = cir.const #cir.int<32> : !u32i + // CHECK-NEXT: cir.return %[[R]] : !u32i + // CHECK-NEXT: } + cir.func @fold_parity() -> !u32i { // 0xdeadbeef is 0b1101_1110_1010_1101_1011_1110_1110_1111 // 0xdeadbeef contains 24 ones @@ -82,6 +122,16 @@ module { // CHECK-NEXT: cir.return %[[R]] : !u32i // CHECK-NEXT: } + cir.func @fold_input_poison() -> !s32i { + %0 = cir.const #cir.poison : !s32i + %1 = cir.clrsb %0 : !s32i + cir.return %1 : !s32i + } + // CHECK-LABEL: @fold_input_poison + // CHECK-NEXT: %[[P:.+]] = cir.const #cir.poison : !s32i + // CHECK-NEXT: cir.return %[[P]] : !s32i + // CHECK-NEXT: } + cir.func @fold_rotate_input_all_zeros(%arg0 : !u32i) -> !u32i { %0 = cir.const #cir.int<0> : !u32i %1 = cir.rotate left %0, %arg0 : !u32i @@ -138,4 +188,24 @@ module { // CHECK-NEXT: %[[R:.+]] = cir.const #cir.int<4024348094> : !u32i // CHECK-NEXT: cir.return %[[R]] : !u32i // CHECK-NEXT: } + + cir.func @fold_rotate_input_poison(%arg0 : !u32i) -> !u32i { + %0 = cir.const #cir.poison : !u32i + %1 = cir.rotate left %0, %arg0 : !u32i + cir.return %1 : !u32i + } + // CHECK-LABEL: @fold_rotate_input_poison + // CHECK-NEXT: %[[P:.+]] = cir.const #cir.poison : !u32i + // CHECK-NEXT: cir.return %[[P]] : !u32i + // CHECK-NEXT: } + + cir.func @fold_rotate_amount_poison(%arg0 : !u32i) -> !u32i { + %0 = cir.const #cir.poison : !u32i + %1 = cir.rotate left %arg0, %0 : !u32i + cir.return %1 : !u32i + } + // CHECK-LABEL: @fold_rotate_amount_poison + // CHECK-NEXT: %[[P:.+]] = cir.const #cir.poison : !u32i + // CHECK-NEXT: cir.return %[[P]] : !u32i + // CHECK-NEXT: } } diff --git a/clang/test/CIR/Transforms/canonicalize.cir b/clang/test/CIR/Transforms/canonicalize.cir index 7ba163e..5daff11 100644 --- a/clang/test/CIR/Transforms/canonicalize.cir +++ b/clang/test/CIR/Transforms/canonicalize.cir @@ -39,6 +39,16 @@ module { // CHECK: cir.func{{.*}} @unary_not(%arg0: !cir.bool) -> !cir.bool // CHECK-NEXT: cir.return %arg0 : !cir.bool + cir.func @unary_poison() -> !s32i { + %0 = cir.const #cir.poison : !s32i + %1 = cir.unary(inc, %0) : !s32i, !s32i + cir.return %1 : !s32i + } + // CHECK: @unary_poison + // CHECK-NEXT: %[[P:.+]] = cir.const #cir.poison : !s32i + // CHECK-NEXT: cir.return %[[P]] : !s32i + // CHECK-NEXT: } + cir.func @cast1(%arg0: !cir.bool) -> !cir.bool { %0 = cir.cast(bool_to_int, %arg0 : !cir.bool), !s32i %1 = cir.cast(int_to_bool, %0 : !s32i), !cir.bool @@ -70,4 +80,14 @@ module { // CHECK-NEXT: %[[CAST3:.*]] = cir.cast(integral, %[[CAST2]] : !s32i), !s64i // CHECK-NEXT: cir.return %[[CAST3]] : !s64i + cir.func @cast_poison() -> !s64i { + %0 = cir.const #cir.poison : !s32i + %1 = cir.cast(integral, %0 : !s32i), !s64i + cir.return %1 : !s64i + } + // CHECK: @cast_poison + // CHECK-NEXT: %[[P:.+]] = cir.const #cir.poison : !s64i + // CHECK-NEXT: cir.return %[[P]] : !s64i + // CHECK-NEXT: } + } diff --git a/clang/test/CXX/basic/basic.link/p19.cppm b/clang/test/CXX/basic/basic.link/p19.cppm new file mode 100644 index 0000000..a0772d7 --- /dev/null +++ b/clang/test/CXX/basic/basic.link/p19.cppm @@ -0,0 +1,71 @@ +// RUN: rm -rf %t +// RUN: mkdir -p %t +// RUN: split-file %s %t +// +// RUN: %clang_cc1 -std=c++20 -emit-reduced-module-interface -verify %t/A.cppm -o %t/A.pcm +// RUN: %clang_cc1 -std=c++20 %t/A.cpp -fmodule-file=A=%t/A.pcm -fsyntax-only -verify + +//--- A.cppm +export module A; +static void f() {} +inline void it() { f(); } // expected-warning {{TU local entity 'f' is exposed}} +static inline void its() { f(); } // OK +template<int> void g() { its(); } // OK +template void g<0>(); + +// Developers Note: We didn't track the use in decltype(). But it should be fine +// since the underlying type is not TU-local. So we're doing nothing bad in practice. +decltype(f) *fp; // error: f (though not its type) is TU-local +auto &fr = f; // OK +// Developers Note: We didn't track the use across variables. In the current implementation, +// we don't know the value of `fr` at compile time, so we failed to detect this. +constexpr auto &fr2 = fr; // error: is an exposure of f +// Developers Note: But if it is a direct use, we are able to detect it. +constexpr auto &fr3 = f; // expected-warning {{TU local entity 'f' is exposed}} +constexpr static auto fp2 = fr; // OK + +struct S { void (&ref)(); } s{f}; // OK, value is TU-local +constexpr extern struct W { S &s; } wrap{s}; // OK, value is not TU-local + +static auto x = []{f();}; // OK +auto x2 = x; // expected-warning {{TU local entity}} +// Developers Note: Why is this an exposure? +int y = ([]{f();}(),0); // error: the closure type is not TU-local +int y2 = (x,0); // OK expected-warning{{left operand of comma operator has no effect}} + +namespace N { + struct A {}; + void adl(A); + static void adl(int); +} +void adl(double); + +inline void h(auto x) { adl(x); } // OK, but certain specializations are exposures + +// Reflection is not supported yet. +// constexpr std::meta::info r1 = ^^g<0>; // OK +// namespace N2 { +// static constexpr std::meta::info r2 = ^^g<1>; // OK, r2 is TU-local +// } +// constexpr std::meta::info r3 = ^^f; // error: r3 is an exposure of f +// +// constexpr auto ctx = std::meta::access_context::current(); +// constexpr std::meta::info r4 = +// std::meta::members_of(^^N2, ctx)[0]; // error: r4 is an exposure of N2​::​r2 + +//--- A.cpp +module A; +void other() { + g<0>(); // OK, specialization is explicitly instantiated + g<1>(); // expected-warning {{instantiation of 'g<1>' triggers reference to TU-local entity 'its' from other TU 'A'}} + // Developers Note: To check use of TU-local entity when overload resolution made. + h(N::A{}); // error: overload set contains TU-local N​::​adl(int) + h(0); // OK, calls adl(double) + adl(N::A{}); // OK; N​::​adl(int) not found, calls N​::​adl(N​::​A) + fr(); // OK, calls f + // Developers Note: To check use of TU-local entity when we're able to detect the TUlocalness + // across variables. + constexpr auto ptr = fr; // error: fr is not usable in constant expressions here + + constexpr auto fptr = f; // expected-error {{use of undeclared identifier 'f'}} +} diff --git a/clang/test/CodeGen/bounds-checking-debuginfo.c b/clang/test/CodeGen/bounds-checking-debuginfo.c index 74c0666..bd7aedd 100644 --- a/clang/test/CodeGen/bounds-checking-debuginfo.c +++ b/clang/test/CodeGen/bounds-checking-debuginfo.c @@ -25,13 +25,13 @@ void d(double*); // CHECK-TRAP-NEXT: [[TMP1:%.*]] = icmp ult i64 [[TMP0]], 10, !dbg [[DBG23]], !nosanitize [[META10]] // CHECK-TRAP-NEXT: br i1 [[TMP1]], label %[[CONT:.*]], label %[[TRAP:.*]], !dbg [[DBG23]], !prof [[PROF27:![0-9]+]], !nosanitize [[META10]] // CHECK-TRAP: [[TRAP]]: -// CHECK-TRAP-NEXT: call void @llvm.ubsantrap(i8 18) #[[ATTR3:[0-9]+]], !dbg [[DBG23]], !nosanitize [[META10]] -// CHECK-TRAP-NEXT: unreachable, !dbg [[DBG23]], !nosanitize [[META10]] +// CHECK-TRAP-NEXT: call void @llvm.ubsantrap(i8 18) #[[ATTR3:[0-9]+]], !dbg [[DBGTRAP:![0-9]+]], !nosanitize [[META10]] +// CHECK-TRAP-NEXT: unreachable, !dbg [[DBGTRAP]], !nosanitize [[META10]] // CHECK-TRAP: [[CONT]]: // CHECK-TRAP-NEXT: [[IDXPROM:%.*]] = sext i32 [[CALL]] to i64, !dbg [[DBG26:![0-9]+]] // CHECK-TRAP-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [10 x double], ptr [[A]], i64 0, i64 [[IDXPROM]], !dbg [[DBG26]] // CHECK-TRAP-NEXT: [[TMP2:%.*]] = load double, ptr [[ARRAYIDX]], align 8, !dbg [[DBG26]] -// CHECK-TRAP-NEXT: ret double [[TMP2]], !dbg [[DBG28:![0-9]+]] +// CHECK-TRAP-NEXT: ret double [[TMP2]], !dbg [[DBG30:![0-9]+]] // // CHECK-NOTRAP-LABEL: define dso_local double @f1( // CHECK-NOTRAP-SAME: i32 noundef [[B:%.*]], i32 noundef [[I:%.*]]) #[[ATTR0:[0-9]+]] !dbg [[DBG4:![0-9]+]] { @@ -93,7 +93,9 @@ double f1(int b, int i) { // CHECK-TRAP: [[META25]] = !DISubroutineType(types: null) // CHECK-TRAP: [[DBG26]] = !DILocation(line: 66, column: 10, scope: [[DBG4]]) // CHECK-TRAP: [[PROF27]] = !{!"branch_weights", i32 1048575, i32 1} -// CHECK-TRAP: [[DBG28]] = !DILocation(line: 66, column: 3, scope: [[DBG4]]) +// CHECK-TRAP: [[DBGTRAP]] = !DILocation(line: 0, scope: [[TRAPMSG:![0-9]+]], inlinedAt: [[DBG23]]) +// CHECK-TRAP: [[TRAPMSG]] = distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer$Array index out of bounds", scope: [[META5]], file: [[META5]], type: [[META25]], flags: DIFlagArtificial, spFlags: DISPFlagDefinition, unit: [[META0]]) +// CHECK-TRAP: [[DBG30]] = !DILocation(line: 66, column: 3, scope: [[DBG4]]) //. // CHECK-NOTRAP: [[META0:![0-9]+]] = distinct !DICompileUnit(language: DW_LANG_C11, file: [[META1:![0-9]+]], isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None) // CHECK-NOTRAP: [[META1]] = !DIFile(filename: "<stdin>", directory: {{.*}}) diff --git a/clang/test/CodeGen/cfi-icall-generalize-debuginfo.c b/clang/test/CodeGen/cfi-icall-generalize-debuginfo.c index 304b605..0ffc2b9 100644 --- a/clang/test/CodeGen/cfi-icall-generalize-debuginfo.c +++ b/clang/test/CodeGen/cfi-icall-generalize-debuginfo.c @@ -30,11 +30,11 @@ int** f(const char *a, const char **b) { // UNGENERALIZED-NEXT: [[TMP0:%.*]] = tail call i1 @llvm.type.test(ptr [[FP]], metadata !"_ZTSFPPiPKcPS2_E"), !dbg [[DBG34:![0-9]+]], !nosanitize [[META38:![0-9]+]] // UNGENERALIZED-NEXT: br i1 [[TMP0]], label %[[CONT:.*]], label %[[TRAP:.*]], !dbg [[DBG34]], !prof [[PROF39:![0-9]+]], !nosanitize [[META38]] // UNGENERALIZED: [[TRAP]]: -// UNGENERALIZED-NEXT: tail call void @llvm.ubsantrap(i8 2) #[[ATTR4:[0-9]+]], !dbg [[DBG34]], !nosanitize [[META38]] -// UNGENERALIZED-NEXT: unreachable, !dbg [[DBG34]], !nosanitize [[META38]] +// UNGENERALIZED-NEXT: tail call void @llvm.ubsantrap(i8 2) #[[ATTR4:[0-9]+]], !dbg [[DBGTRAP:![0-9]+]], !nosanitize [[META38]] +// UNGENERALIZED-NEXT: unreachable, !dbg [[DBGTRAP]], !nosanitize [[META38]] // UNGENERALIZED: [[CONT]]: // UNGENERALIZED-NEXT: [[CALL:%.*]] = tail call ptr [[FP]](ptr noundef null, ptr noundef null) #[[ATTR5:[0-9]+]], !dbg [[DBG37:![0-9]+]] -// UNGENERALIZED-NEXT: ret void, !dbg [[DBG40:![0-9]+]] +// UNGENERALIZED-NEXT: ret void, !dbg [[DBG42:![0-9]+]] // // GENERALIZED-LABEL: define dso_local void @g( // GENERALIZED-SAME: ptr noundef [[FP:%.*]]) local_unnamed_addr #[[ATTR1:[0-9]+]] !dbg [[DBG25:![0-9]+]] !type [[META31:![0-9]+]] !type [[META32:![0-9]+]] { @@ -43,11 +43,11 @@ int** f(const char *a, const char **b) { // GENERALIZED-NEXT: [[TMP0:%.*]] = tail call i1 @llvm.type.test(ptr [[FP]], metadata !"_ZTSFPvPKvS_E.generalized"), !dbg [[DBG34:![0-9]+]], !nosanitize [[META38:![0-9]+]] // GENERALIZED-NEXT: br i1 [[TMP0]], label %[[CONT:.*]], label %[[TRAP:.*]], !dbg [[DBG34]], !prof [[PROF39:![0-9]+]], !nosanitize [[META38]] // GENERALIZED: [[TRAP]]: -// GENERALIZED-NEXT: tail call void @llvm.ubsantrap(i8 2) #[[ATTR4:[0-9]+]], !dbg [[DBG34]], !nosanitize [[META38]] -// GENERALIZED-NEXT: unreachable, !dbg [[DBG34]], !nosanitize [[META38]] +// GENERALIZED-NEXT: tail call void @llvm.ubsantrap(i8 2) #[[ATTR4:[0-9]+]], !dbg [[DBGTRAP:![0-9]+]], !nosanitize [[META38]] +// GENERALIZED-NEXT: unreachable, !dbg [[DBGTRAP]], !nosanitize [[META38]] // GENERALIZED: [[CONT]]: // GENERALIZED-NEXT: [[CALL:%.*]] = tail call ptr [[FP]](ptr noundef null, ptr noundef null) #[[ATTR5:[0-9]+]], !dbg [[DBG37:![0-9]+]] -// GENERALIZED-NEXT: ret void, !dbg [[DBG40:![0-9]+]] +// GENERALIZED-NEXT: ret void, !dbg [[DBG42:![0-9]+]] // void g(int** (*fp)(const char *, const char **)) { fp(0, 0); @@ -90,7 +90,9 @@ void g(int** (*fp)(const char *, const char **)) { // UNGENERALIZED: [[DBG37]] = !DILocation(line: 53, column: 3, scope: [[DBG25]]) // UNGENERALIZED: [[META38]] = !{} // UNGENERALIZED: [[PROF39]] = !{!"branch_weights", i32 1048575, i32 1} -// UNGENERALIZED: [[DBG40]] = !DILocation(line: 54, column: 1, scope: [[DBG25]]) +// UNGENERALIZED: [[DBGTRAP]] = !DILocation(line: 0, scope: [[TRAPMSG:![0-9]+]], inlinedAt: [[DBG34]]) +// UNGENERALIZED: [[TRAPMSG]] = distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer$Control flow integrity check failed", scope: [[META11]], file: [[META11]], type: [[META36]], flags: DIFlagArtificial, spFlags: DISPFlagDefinition, unit: [[META0]]) +// UNGENERALIZED: [[DBG42]] = !DILocation(line: 54, column: 1, scope: [[DBG25]]) //. // GENERALIZED: [[META0:![0-9]+]] = distinct !DICompileUnit(language: DW_LANG_C11, file: [[META1:![0-9]+]], isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, retainedTypes: [[META2:![0-9]+]], splitDebugInlining: false, nameTableKind: None) // GENERALIZED: [[META1]] = !DIFile(filename: "{{.*}}<stdin>", directory: {{.*}}) @@ -128,5 +130,7 @@ void g(int** (*fp)(const char *, const char **)) { // GENERALIZED: [[DBG37]] = !DILocation(line: 53, column: 3, scope: [[DBG25]]) // GENERALIZED: [[META38]] = !{} // GENERALIZED: [[PROF39]] = !{!"branch_weights", i32 1048575, i32 1} -// GENERALIZED: [[DBG40]] = !DILocation(line: 54, column: 1, scope: [[DBG25]]) +// GENERALIZED: [[DBGTRAP]] = !DILocation(line: 0, scope: [[TRAPMSG:![0-9]+]], inlinedAt: [[DBG34]]) +// GENERALIZED: [[TRAPMSG]] = distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer$Control flow integrity check failed", scope: [[META11]], file: [[META11]], type: [[META36]], flags: DIFlagArtificial, spFlags: DISPFlagDefinition, unit: [[META0]]) +// GENERALIZED: [[DBG42]] = !DILocation(line: 54, column: 1, scope: [[DBG25]]) //. diff --git a/clang/test/CodeGen/cfi-icall-normalize2-debuginfo.c b/clang/test/CodeGen/cfi-icall-normalize2-debuginfo.c index a2f6ee0c..258c3bf 100644 --- a/clang/test/CodeGen/cfi-icall-normalize2-debuginfo.c +++ b/clang/test/CodeGen/cfi-icall-normalize2-debuginfo.c @@ -15,50 +15,50 @@ // CHECK-NEXT: [[TMP0:%.*]] = tail call i1 @llvm.type.test(ptr [[FN]], metadata !"_ZTSFvu3i32E.normalized"), !dbg [[DBG21:![0-9]+]], !nosanitize [[META25:![0-9]+]] // CHECK-NEXT: br i1 [[TMP0]], label %[[CONT:.*]], label %[[TRAP:.*]], !dbg [[DBG21]], !prof [[PROF26:![0-9]+]], !nosanitize [[META25]] // CHECK: [[TRAP]]: -// CHECK-NEXT: tail call void @llvm.ubsantrap(i8 2) #[[ATTR3:[0-9]+]], !dbg [[DBG21]], !nosanitize [[META25]] -// CHECK-NEXT: unreachable, !dbg [[DBG21]], !nosanitize [[META25]] +// CHECK-NEXT: tail call void @llvm.ubsantrap(i8 2) #[[ATTR3:[0-9]+]], !dbg [[DBGTRAP:![0-9]+]], !nosanitize [[META25]] +// CHECK-NEXT: unreachable, !dbg [[DBGTRAP]], !nosanitize [[META25]] // CHECK: [[CONT]]: // CHECK-NEXT: tail call void [[FN]](i32 noundef [[ARG]]) #[[ATTR4:[0-9]+]], !dbg [[DBG24:![0-9]+]] -// CHECK-NEXT: ret void, !dbg [[DBG27:![0-9]+]] +// CHECK-NEXT: ret void, !dbg [[DBG29:![0-9]+]] // void foo(void (*fn)(int), int arg) { fn(arg); } // CHECK-LABEL: define dso_local void @bar( -// CHECK-SAME: ptr noundef [[FN:%.*]], i32 noundef [[ARG1:%.*]], i32 noundef [[ARG2:%.*]]) local_unnamed_addr #[[ATTR0]] !dbg [[DBG28:![0-9]+]] !type [[META38:![0-9]+]] !type [[META39:![0-9]+]] { +// CHECK-SAME: ptr noundef [[FN:%.*]], i32 noundef [[ARG1:%.*]], i32 noundef [[ARG2:%.*]]) local_unnamed_addr #[[ATTR0]] !dbg [[DBG30:![0-9]+]] !type [[META40:![0-9]+]] !type [[META41:![0-9]+]] { // CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: #dbg_value(ptr [[FN]], [[META35:![0-9]+]], !DIExpression(), [[META40:![0-9]+]]) -// CHECK-NEXT: #dbg_value(i32 [[ARG1]], [[META36:![0-9]+]], !DIExpression(), [[META40]]) -// CHECK-NEXT: #dbg_value(i32 [[ARG2]], [[META37:![0-9]+]], !DIExpression(), [[META40]]) -// CHECK-NEXT: [[TMP0:%.*]] = tail call i1 @llvm.type.test(ptr [[FN]], metadata !"_ZTSFvu3i32S_E.normalized"), !dbg [[DBG41:![0-9]+]], !nosanitize [[META25]] -// CHECK-NEXT: br i1 [[TMP0]], label %[[CONT:.*]], label %[[TRAP:.*]], !dbg [[DBG41]], !prof [[PROF26]], !nosanitize [[META25]] +// CHECK-NEXT: #dbg_value(ptr [[FN]], [[META37:![0-9]+]], !DIExpression(), [[META42:![0-9]+]]) +// CHECK-NEXT: #dbg_value(i32 [[ARG1]], [[META38:![0-9]+]], !DIExpression(), [[META42]]) +// CHECK-NEXT: #dbg_value(i32 [[ARG2]], [[META39:![0-9]+]], !DIExpression(), [[META42]]) +// CHECK-NEXT: [[TMP0:%.*]] = tail call i1 @llvm.type.test(ptr [[FN]], metadata !"_ZTSFvu3i32S_E.normalized"), !dbg [[DBG43:![0-9]+]], !nosanitize [[META25]] +// CHECK-NEXT: br i1 [[TMP0]], label %[[CONT:.*]], label %[[TRAP:.*]], !dbg [[DBG43]], !prof [[PROF26]], !nosanitize [[META25]] // CHECK: [[TRAP]]: -// CHECK-NEXT: tail call void @llvm.ubsantrap(i8 2) #[[ATTR3]], !dbg [[DBG41]], !nosanitize [[META25]] -// CHECK-NEXT: unreachable, !dbg [[DBG41]], !nosanitize [[META25]] +// CHECK-NEXT: tail call void @llvm.ubsantrap(i8 2) #[[ATTR3]], !dbg [[DBG45:![0-9]+]], !nosanitize [[META25]] +// CHECK-NEXT: unreachable, !dbg [[DBG45]], !nosanitize [[META25]] // CHECK: [[CONT]]: -// CHECK-NEXT: tail call void [[FN]](i32 noundef [[ARG1]], i32 noundef [[ARG2]]) #[[ATTR4]], !dbg [[DBG42:![0-9]+]] -// CHECK-NEXT: ret void, !dbg [[DBG43:![0-9]+]] +// CHECK-NEXT: tail call void [[FN]](i32 noundef [[ARG1]], i32 noundef [[ARG2]]) #[[ATTR4]], !dbg [[DBG44:![0-9]+]] +// CHECK-NEXT: ret void, !dbg [[DBG46:![0-9]+]] // void bar(void (*fn)(int, int), int arg1, int arg2) { fn(arg1, arg2); } // CHECK-LABEL: define dso_local void @baz( -// CHECK-SAME: ptr noundef [[FN:%.*]], i32 noundef [[ARG1:%.*]], i32 noundef [[ARG2:%.*]], i32 noundef [[ARG3:%.*]]) local_unnamed_addr #[[ATTR0]] !dbg [[DBG44:![0-9]+]] !type [[META55:![0-9]+]] !type [[META56:![0-9]+]] { +// CHECK-SAME: ptr noundef [[FN:%.*]], i32 noundef [[ARG1:%.*]], i32 noundef [[ARG2:%.*]], i32 noundef [[ARG3:%.*]]) local_unnamed_addr #[[ATTR0]] !dbg [[DBG47:![0-9]+]] !type [[META58:![0-9]+]] !type [[META59:![0-9]+]] { // CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: #dbg_value(ptr [[FN]], [[META51:![0-9]+]], !DIExpression(), [[META57:![0-9]+]]) -// CHECK-NEXT: #dbg_value(i32 [[ARG1]], [[META52:![0-9]+]], !DIExpression(), [[META57]]) -// CHECK-NEXT: #dbg_value(i32 [[ARG2]], [[META53:![0-9]+]], !DIExpression(), [[META57]]) -// CHECK-NEXT: #dbg_value(i32 [[ARG3]], [[META54:![0-9]+]], !DIExpression(), [[META57]]) -// CHECK-NEXT: [[TMP0:%.*]] = tail call i1 @llvm.type.test(ptr [[FN]], metadata !"_ZTSFvu3i32S_S_E.normalized"), !dbg [[DBG58:![0-9]+]], !nosanitize [[META25]] -// CHECK-NEXT: br i1 [[TMP0]], label %[[CONT:.*]], label %[[TRAP:.*]], !dbg [[DBG58]], !prof [[PROF26]], !nosanitize [[META25]] +// CHECK-NEXT: #dbg_value(ptr [[FN]], [[META54:![0-9]+]], !DIExpression(), [[META60:![0-9]+]]) +// CHECK-NEXT: #dbg_value(i32 [[ARG1]], [[META55:![0-9]+]], !DIExpression(), [[META60]]) +// CHECK-NEXT: #dbg_value(i32 [[ARG2]], [[META56:![0-9]+]], !DIExpression(), [[META60]]) +// CHECK-NEXT: #dbg_value(i32 [[ARG3]], [[META57:![0-9]+]], !DIExpression(), [[META60]]) +// CHECK-NEXT: [[TMP0:%.*]] = tail call i1 @llvm.type.test(ptr [[FN]], metadata !"_ZTSFvu3i32S_S_E.normalized"), !dbg [[DBG61:![0-9]+]], !nosanitize [[META25]] +// CHECK-NEXT: br i1 [[TMP0]], label %[[CONT:.*]], label %[[TRAP:.*]], !dbg [[DBG61]], !prof [[PROF26]], !nosanitize [[META25]] // CHECK: [[TRAP]]: -// CHECK-NEXT: tail call void @llvm.ubsantrap(i8 2) #[[ATTR3]], !dbg [[DBG58]], !nosanitize [[META25]] -// CHECK-NEXT: unreachable, !dbg [[DBG58]], !nosanitize [[META25]] +// CHECK-NEXT: tail call void @llvm.ubsantrap(i8 2) #[[ATTR3]], !dbg [[DBG63:![0-9]+]], !nosanitize [[META25]] +// CHECK-NEXT: unreachable, !dbg [[DBG63]], !nosanitize [[META25]] // CHECK: [[CONT]]: -// CHECK-NEXT: tail call void [[FN]](i32 noundef [[ARG1]], i32 noundef [[ARG2]], i32 noundef [[ARG3]]) #[[ATTR4]], !dbg [[DBG59:![0-9]+]] -// CHECK-NEXT: ret void, !dbg [[DBG60:![0-9]+]] +// CHECK-NEXT: tail call void [[FN]](i32 noundef [[ARG1]], i32 noundef [[ARG2]], i32 noundef [[ARG3]]) #[[ATTR4]], !dbg [[DBG62:![0-9]+]] +// CHECK-NEXT: ret void, !dbg [[DBG64:![0-9]+]] // void baz(void (*fn)(int, int, int), int arg1, int arg2, int arg3) { fn(arg1, arg2, arg3); @@ -87,38 +87,42 @@ void baz(void (*fn)(int, int, int), int arg1, int arg2, int arg3) { // CHECK: [[DBG24]] = !DILocation(line: 25, column: 5, scope: [[DBG7]]) // CHECK: [[META25]] = !{} // CHECK: [[PROF26]] = !{!"branch_weights", i32 1048575, i32 1} -// CHECK: [[DBG27]] = !DILocation(line: 26, column: 1, scope: [[DBG7]]) -// CHECK: [[DBG28]] = distinct !DISubprogram(name: "bar", scope: [[META8]], file: [[META8]], line: 43, type: [[META29:![0-9]+]], scopeLine: 43, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: [[META0]], retainedNodes: [[META34:![0-9]+]]) -// CHECK: [[META29]] = !DISubroutineType(types: [[META30:![0-9]+]]) -// CHECK: [[META30]] = !{null, [[META31:![0-9]+]], [[META14]], [[META14]]} -// CHECK: [[META31]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: [[META32:![0-9]+]], size: 64) -// CHECK: [[META32]] = !DISubroutineType(types: [[META33:![0-9]+]]) -// CHECK: [[META33]] = !{null, [[META14]], [[META14]]} -// CHECK: [[META34]] = !{[[META35]], [[META36]], [[META37]]} -// CHECK: [[META35]] = !DILocalVariable(name: "fn", arg: 1, scope: [[DBG28]], file: [[META8]], line: 43, type: [[META31]]) -// CHECK: [[META36]] = !DILocalVariable(name: "arg1", arg: 2, scope: [[DBG28]], file: [[META8]], line: 43, type: [[META14]]) -// CHECK: [[META37]] = !DILocalVariable(name: "arg2", arg: 3, scope: [[DBG28]], file: [[META8]], line: 43, type: [[META14]]) -// CHECK: [[META38]] = !{i64 0, !"_ZTSFvPFvu3i32S_ES_S_E.normalized"} -// CHECK: [[META39]] = !{i64 0, !"_ZTSFvPvu3i32S0_E.normalized.generalized"} -// CHECK: [[META40]] = !DILocation(line: 0, scope: [[DBG28]]) -// CHECK: [[DBG41]] = !DILocation(line: 0, scope: [[META22]], inlinedAt: [[DBG42]]) -// CHECK: [[DBG42]] = !DILocation(line: 44, column: 5, scope: [[DBG28]]) -// CHECK: [[DBG43]] = !DILocation(line: 45, column: 1, scope: [[DBG28]]) -// CHECK: [[DBG44]] = distinct !DISubprogram(name: "baz", scope: [[META8]], file: [[META8]], line: 63, type: [[META45:![0-9]+]], scopeLine: 63, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: [[META0]], retainedNodes: [[META50:![0-9]+]]) -// CHECK: [[META45]] = !DISubroutineType(types: [[META46:![0-9]+]]) -// CHECK: [[META46]] = !{null, [[META47:![0-9]+]], [[META14]], [[META14]], [[META14]]} -// CHECK: [[META47]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: [[META48:![0-9]+]], size: 64) +// CHECK: [[DBGTRAP]] = !DILocation(line: 0, scope: [[TRAPMSG:![0-9]+]], inlinedAt: [[DBG21]]) +// CHECK: [[TRAPMSG]] = distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer$Control flow integrity check failed", scope: [[META8]], file: [[META8]], type: [[META23]], flags: DIFlagArtificial, spFlags: DISPFlagDefinition, unit: [[META0]]) +// CHECK: [[DBG29]] = !DILocation(line: 26, column: 1, scope: [[DBG7]]) +// CHECK: [[DBG30]] = distinct !DISubprogram(name: "bar", scope: [[META8]], file: [[META8]], line: 43, type: [[META31:![0-9]+]], scopeLine: 43, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: [[META0]], retainedNodes: [[META36:![0-9]+]]) +// CHECK: [[META31]] = !DISubroutineType(types: [[META32:![0-9]+]]) +// CHECK: [[META32]] = !{null, [[META33:![0-9]+]], [[META14]], [[META14]]} +// CHECK: [[META33]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: [[META34:![0-9]+]], size: 64) +// CHECK: [[META34]] = !DISubroutineType(types: [[META35:![0-9]+]]) +// CHECK: [[META35]] = !{null, [[META14]], [[META14]]} +// CHECK: [[META36]] = !{[[META37]], [[META38]], [[META39]]} +// CHECK: [[META37]] = !DILocalVariable(name: "fn", arg: 1, scope: [[DBG30]], file: [[META8]], line: 43, type: [[META33]]) +// CHECK: [[META38]] = !DILocalVariable(name: "arg1", arg: 2, scope: [[DBG30]], file: [[META8]], line: 43, type: [[META14]]) +// CHECK: [[META39]] = !DILocalVariable(name: "arg2", arg: 3, scope: [[DBG30]], file: [[META8]], line: 43, type: [[META14]]) +// CHECK: [[META40]] = !{i64 0, !"_ZTSFvPFvu3i32S_ES_S_E.normalized"} +// CHECK: [[META41]] = !{i64 0, !"_ZTSFvPvu3i32S0_E.normalized.generalized"} +// CHECK: [[META42]] = !DILocation(line: 0, scope: [[DBG30]]) +// CHECK: [[DBG43]] = !DILocation(line: 0, scope: [[META22]], inlinedAt: [[DBG44]]) +// CHECK: [[DBG44]] = !DILocation(line: 44, column: 5, scope: [[DBG30]]) +// CHECK: [[DBG45]] = !DILocation(line: 0, scope: [[TRAPMSG]], inlinedAt: [[DBG43]]) +// CHECK: [[DBG46]] = !DILocation(line: 45, column: 1, scope: [[DBG30]]) +// CHECK: [[DBG47]] = distinct !DISubprogram(name: "baz", scope: [[META8]], file: [[META8]], line: 63, type: [[META48:![0-9]+]], scopeLine: 63, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: [[META0]], retainedNodes: [[META53:![0-9]+]]) // CHECK: [[META48]] = !DISubroutineType(types: [[META49:![0-9]+]]) -// CHECK: [[META49]] = !{null, [[META14]], [[META14]], [[META14]]} -// CHECK: [[META50]] = !{[[META51]], [[META52]], [[META53]], [[META54]]} -// CHECK: [[META51]] = !DILocalVariable(name: "fn", arg: 1, scope: [[DBG44]], file: [[META8]], line: 63, type: [[META47]]) -// CHECK: [[META52]] = !DILocalVariable(name: "arg1", arg: 2, scope: [[DBG44]], file: [[META8]], line: 63, type: [[META14]]) -// CHECK: [[META53]] = !DILocalVariable(name: "arg2", arg: 3, scope: [[DBG44]], file: [[META8]], line: 63, type: [[META14]]) -// CHECK: [[META54]] = !DILocalVariable(name: "arg3", arg: 4, scope: [[DBG44]], file: [[META8]], line: 63, type: [[META14]]) -// CHECK: [[META55]] = !{i64 0, !"_ZTSFvPFvu3i32S_S_ES_S_S_E.normalized"} -// CHECK: [[META56]] = !{i64 0, !"_ZTSFvPvu3i32S0_S0_E.normalized.generalized"} -// CHECK: [[META57]] = !DILocation(line: 0, scope: [[DBG44]]) -// CHECK: [[DBG58]] = !DILocation(line: 0, scope: [[META22]], inlinedAt: [[DBG59]]) -// CHECK: [[DBG59]] = !DILocation(line: 64, column: 5, scope: [[DBG44]]) -// CHECK: [[DBG60]] = !DILocation(line: 65, column: 1, scope: [[DBG44]]) +// CHECK: [[META49]] = !{null, [[META50:![0-9]+]], [[META14]], [[META14]], [[META14]]} +// CHECK: [[META50]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: [[META51:![0-9]+]], size: 64) +// CHECK: [[META51]] = !DISubroutineType(types: [[META52:![0-9]+]]) +// CHECK: [[META52]] = !{null, [[META14]], [[META14]], [[META14]]} +// CHECK: [[META53]] = !{[[META54]], [[META55]], [[META56]], [[META57]]} +// CHECK: [[META54]] = !DILocalVariable(name: "fn", arg: 1, scope: [[DBG47]], file: [[META8]], line: 63, type: [[META50]]) +// CHECK: [[META55]] = !DILocalVariable(name: "arg1", arg: 2, scope: [[DBG47]], file: [[META8]], line: 63, type: [[META14]]) +// CHECK: [[META56]] = !DILocalVariable(name: "arg2", arg: 3, scope: [[DBG47]], file: [[META8]], line: 63, type: [[META14]]) +// CHECK: [[META57]] = !DILocalVariable(name: "arg3", arg: 4, scope: [[DBG47]], file: [[META8]], line: 63, type: [[META14]]) +// CHECK: [[META58]] = !{i64 0, !"_ZTSFvPFvu3i32S_S_ES_S_S_E.normalized"} +// CHECK: [[META59]] = !{i64 0, !"_ZTSFvPvu3i32S0_S0_E.normalized.generalized"} +// CHECK: [[META60]] = !DILocation(line: 0, scope: [[DBG47]]) +// CHECK: [[DBG61]] = !DILocation(line: 0, scope: [[META22]], inlinedAt: [[DBG62]]) +// CHECK: [[DBG62]] = !DILocation(line: 64, column: 5, scope: [[DBG47]]) +// CHECK: [[DBG63]] = !DILocation(line: 0, scope: [[TRAPMSG]], inlinedAt: [[DBG61]]) +// CHECK: [[DBG64]] = !DILocation(line: 65, column: 1, scope: [[DBG47]]) //. diff --git a/clang/test/CodeGen/ubsan-trap-debugloc.c b/clang/test/CodeGen/ubsan-trap-debugloc.c index 87cbfad..2f5258a 100644 --- a/clang/test/CodeGen/ubsan-trap-debugloc.c +++ b/clang/test/CodeGen/ubsan-trap-debugloc.c @@ -20,5 +20,8 @@ void bar(volatile int a) __attribute__((optnone)) { // CHECK: [[LOC]] = !DILocation(line: 0 // With optimisations disabled the traps are not merged and retain accurate debug locations -// CHECK: [[LOC2]] = !DILocation(line: 15, column: 9 -// CHECK: [[LOC3]] = !DILocation(line: 16, column: 9 + // CHECK-DAG: [[SRC2:![0-9]+]] = !DILocation(line: 15, column: 9, + // CHECK-DAG: [[SRC3:![0-9]+]] = !DILocation(line: 16, column: 9, + // CHECK-DAG: [[LOC2]] = !DILocation(line: 0, scope: [[SCOPE2:![0-9]+]], inlinedAt: [[SRC2]]) + // CHECK-DAG: [[LOC3]] = !DILocation(line: 0, scope: [[SCOPE3:![0-9]+]], inlinedAt: [[SRC3]]) + diff --git a/clang/test/CodeGen/ubsan-trap-reason-add-overflow.c b/clang/test/CodeGen/ubsan-trap-reason-add-overflow.c new file mode 100644 index 0000000..225778d --- /dev/null +++ b/clang/test/CodeGen/ubsan-trap-reason-add-overflow.c @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \ +// RUN: -fsanitize=signed-integer-overflow -fsanitize-trap=signed-integer-overflow -emit-llvm %s -o - | FileCheck %s + +int add_overflow(int a, int b) { return a + b; } + +// CHECK-LABEL: @add_overflow +// CHECK: call void @llvm.ubsantrap(i8 0) {{.*}}!dbg [[LOC:![0-9]+]] +// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}}) +// CHECK: [[MSG]] = distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer$Integer addition overflowed" diff --git a/clang/test/CodeGen/ubsan-trap-reason-alignment-assumption.c b/clang/test/CodeGen/ubsan-trap-reason-alignment-assumption.c new file mode 100644 index 0000000..3247ceb --- /dev/null +++ b/clang/test/CodeGen/ubsan-trap-reason-alignment-assumption.c @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \ +// RUN: -fsanitize=alignment -fsanitize-trap=alignment -emit-llvm %s -o - | FileCheck %s + +#include <stdint.h> +int32_t *get_int(void) __attribute__((assume_aligned(16))); + +void retrieve_int(void) { + int *i = get_int(); + *i = 7; +} + +// CHECK-LABEL: @retrieve_int +// CHECK: call void @llvm.ubsantrap(i8 23) {{.*}}!dbg [[LOC:![0-9]+]] +// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}}) +// CHECK: [[MSG]] = distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer$Alignment assumption violated" diff --git a/clang/test/CodeGen/ubsan-trap-reason-builtin-unreachable.c b/clang/test/CodeGen/ubsan-trap-reason-builtin-unreachable.c new file mode 100644 index 0000000..97bd690 --- /dev/null +++ b/clang/test/CodeGen/ubsan-trap-reason-builtin-unreachable.c @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \ +// RUN: -fsanitize=unreachable -fsanitize-trap=unreachable -emit-llvm %s -o - | FileCheck %s + +int call_builtin_unreachable(void) { __builtin_unreachable(); } + +// CHECK-LABEL: @call_builtin_unreachable +// CHECK: call void @llvm.ubsantrap(i8 1) {{.*}}!dbg [[LOC:![0-9]+]] +// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}}) +// CHECK: [[MSG]] = distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer$_builtin_unreachable(), execution reached an unreachable program point" diff --git a/clang/test/CodeGen/ubsan-trap-reason-cfi-check-fail.c b/clang/test/CodeGen/ubsan-trap-reason-cfi-check-fail.c new file mode 100644 index 0000000..9304f51 --- /dev/null +++ b/clang/test/CodeGen/ubsan-trap-reason-cfi-check-fail.c @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \ +// RUN: -fsanitize=cfi-icall -fsanitize-trap=cfi-icall -emit-llvm %s -o - | FileCheck %s + +typedef int (*fp_t)(int); + +int good(int x) { return x + 1; } + +int bad(void) { return 0; } + +int cfi_trigger(int a) { + fp_t p = good; + int r1 = p(a); + + p = (fp_t)(void *)bad; + int r2 = p(a); + + return r1 + r2; +} + +// CHECK-LABEL: @good +// CHECK-LABEL: @bad +// CHECK-LABEL: @cfi_trigger +// CHECK: call void @llvm.ubsantrap(i8 2) {{.*}}!dbg [[LOC:![0-9]+]] +// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}}) +// CHECK: [[MSG]] = distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer$Control flow integrity check failed" diff --git a/clang/test/CodeGen/ubsan-trap-reason-crash.cpp b/clang/test/CodeGen/ubsan-trap-reason-crash.cpp new file mode 100644 index 0000000..6add9bf --- /dev/null +++ b/clang/test/CodeGen/ubsan-trap-reason-crash.cpp @@ -0,0 +1,20 @@ +// FIXME: We should emit a trap message for this case too. +// But sometimes Clang will emit a ubsan trap into the prologue of a function, +// at which point the debug-info locations haven't been set up yet and +// can't hook up our artificial inline frame. [Issue #150707] + +// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \ +// RUN: -fsanitize=null -fsanitize-trap=null -emit-llvm %s -o - | FileCheck %s + +struct Foo { + void target() {} +} f; + +void caller() { + f.target(); +} + + +// CHECK-LABEL: @_Z6callerv +// CHECK: call void @llvm.ubsantrap(i8 22){{.*}}!nosanitize +// CHECK-NOT: __clang_trap_msg diff --git a/clang/test/CodeGen/ubsan-trap-reason-div-rem-overflow.c b/clang/test/CodeGen/ubsan-trap-reason-div-rem-overflow.c new file mode 100644 index 0000000..d0b21dd --- /dev/null +++ b/clang/test/CodeGen/ubsan-trap-reason-div-rem-overflow.c @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \ +// RUN: -fsanitize=signed-integer-overflow -fsanitize-trap=signed-integer-overflow -emit-llvm %s -o - | FileCheck %s + +int div_rem_overflow(int a, int b) { return a / b; } + +// CHECK-LABEL: @div_rem_overflow +// CHECK: call void @llvm.ubsantrap(i8 3) {{.*}}!dbg [[LOC:![0-9]+]] +// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}}) +// CHECK: [[MSG]] = distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer$Integer divide or remainder overflowed" diff --git a/clang/test/CodeGen/ubsan-trap-reason-dynamic-type-cache-miss.cpp b/clang/test/CodeGen/ubsan-trap-reason-dynamic-type-cache-miss.cpp new file mode 100644 index 0000000..f89fbdcf --- /dev/null +++ b/clang/test/CodeGen/ubsan-trap-reason-dynamic-type-cache-miss.cpp @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \ +// RUN: -fsanitize=vptr -fsanitize-trap=vptr -emit-llvm %s -o - | FileCheck %s + +struct A { + virtual void foo(); +}; +struct B { + virtual void bar(); +}; + +void A::foo() {} +void B::bar() {} + +int dynamic_type_cache_miss() { + B b; + A &a = reinterpret_cast<A &>(b); + a.foo(); + return 0; +} + +// CHECK-LABEL: @_ZN1A3fooEv +// CHECK-LABEL: @_ZN1B3barEv +// CHECK-LABEL: @_Z23dynamic_type_cache_missv +// CHECK: call void @llvm.ubsantrap(i8 4) {{.*}}!dbg [[LOC:![0-9]+]] +// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}}) +// CHECK: [[MSG]] = distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer$Dynamic type cache miss, member call made on an object whose dynamic type differs from the expected type" diff --git a/clang/test/CodeGen/ubsan-trap-reason-flag.c b/clang/test/CodeGen/ubsan-trap-reason-flag.c new file mode 100644 index 0000000..5cc16d1 --- /dev/null +++ b/clang/test/CodeGen/ubsan-trap-reason-flag.c @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \ +// RUN: -fsanitize=signed-integer-overflow -fsanitize-trap=signed-integer-overflow -emit-llvm %s -o - \ +// RUN: | FileCheck %s --check-prefix=ANNOTATE + +// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \ +// RUN: -fsanitize=signed-integer-overflow -fsanitize-trap=signed-integer-overflow \ +// RUN: -fsanitize-debug-trap-reasons -emit-llvm %s -o - | FileCheck %s --check-prefix=ANNOTATE + +// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \ +// RUN: -fsanitize=signed-integer-overflow -fsanitize-trap=signed-integer-overflow \ +// RUN: -fno-sanitize-debug-trap-reasons -emit-llvm %s -o - | FileCheck %s --check-prefix=NO-ANNOTATE + +int add_overflow(int a, int b) { return a + b; } + +// ANNOTATE-LABEL: @add_overflow +// ANNOTATE: call void @llvm.ubsantrap(i8 0) {{.*}}!dbg [[LOC:![0-9]+]] +// ANNOTATE: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}}) +// ANNOTATE: [[MSG]] = distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer$Integer addition overflowed" + +// NO-ANNOTATE-LABEL: @add_overflow +// NO-ANNOTATE: call void @llvm.ubsantrap(i8 0) {{.*}}!dbg [[LOC:![0-9]+]] +// NO-ANNOTATE-NOT: __clang_trap_msg diff --git a/clang/test/CodeGen/ubsan-trap-reason-float-cast-overflow.c b/clang/test/CodeGen/ubsan-trap-reason-float-cast-overflow.c new file mode 100644 index 0000000..079a191e --- /dev/null +++ b/clang/test/CodeGen/ubsan-trap-reason-float-cast-overflow.c @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \ +// RUN: -fsanitize=float-cast-overflow -fsanitize-trap=float-cast-overflow -emit-llvm %s -o - | FileCheck %s + +int float_cast_overflow(float x) { return (int)x; } + +// CHECK-LABEL: @float_cast_overflow +// CHECK: call void @llvm.ubsantrap(i8 5) {{.*}}!dbg [[LOC:![0-9]+]] +// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}}) +// CHECK: [[MSG]] = distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer$Floating-point to integer conversion overflowed" diff --git a/clang/test/CodeGen/ubsan-trap-reason-function-type-mismatch.c b/clang/test/CodeGen/ubsan-trap-reason-function-type-mismatch.c new file mode 100644 index 0000000..1727f9c --- /dev/null +++ b/clang/test/CodeGen/ubsan-trap-reason-function-type-mismatch.c @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \ +// RUN: -fsanitize=function -fsanitize-trap=function -emit-llvm %s -o - | FileCheck %s + +void target(void) {} + +int function_type_mismatch(void) { + int (*fp_int)(int); + + fp_int = (int (*)(int))(void *)target; + + return fp_int(42); +} + +// CHECK-LABEL: @target +// CHECK-LABEL: @function_type_mismatch +// CHECK: call void @llvm.ubsantrap(i8 6) {{.*}}!dbg [[LOC:![0-9]+]] +// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}}) +// CHECK: [[MSG]] = distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer$Function called with mismatched signature" diff --git a/clang/test/CodeGen/ubsan-trap-reason-implicit-conversion.c b/clang/test/CodeGen/ubsan-trap-reason-implicit-conversion.c new file mode 100644 index 0000000..43c091d --- /dev/null +++ b/clang/test/CodeGen/ubsan-trap-reason-implicit-conversion.c @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \ +// RUN: -fsanitize=implicit-unsigned-integer-truncation -fsanitize-trap=implicit-unsigned-integer-truncation -emit-llvm %s -o - | FileCheck %s + +unsigned long long big; + +unsigned implicit_conversion(void) { return big; } + +// CHECK-LABEL: @implicit_conversion +// CHECK: call void @llvm.ubsantrap(i8 7) {{.*}}!dbg [[LOC:![0-9]+]] +// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}}) +// CHECK: [[MSG]] = distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer$Implicit integer conversion overflowed or lost data" diff --git a/clang/test/CodeGen/ubsan-trap-reason-invalid-builtin.c b/clang/test/CodeGen/ubsan-trap-reason-invalid-builtin.c new file mode 100644 index 0000000..56cf674 --- /dev/null +++ b/clang/test/CodeGen/ubsan-trap-reason-invalid-builtin.c @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \ +// RUN: -fsanitize=builtin -fsanitize-trap=builtin -emit-llvm %s -o - | FileCheck %s + +unsigned invalid_builtin(unsigned x) { return __builtin_clz(x); } + +// CHECK-LABEL: @invalid_builtin +// CHECK: call void @llvm.ubsantrap(i8 8) {{.*}}!dbg [[LOC:![0-9]+]] +// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}}) +// CHECK: [[MSG]] = distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer$Invalid use of builtin function" diff --git a/clang/test/CodeGen/ubsan-trap-reason-invalid-objc-cast.m b/clang/test/CodeGen/ubsan-trap-reason-invalid-objc-cast.m new file mode 100644 index 0000000..ed2d5ff --- /dev/null +++ b/clang/test/CodeGen/ubsan-trap-reason-invalid-objc-cast.m @@ -0,0 +1,32 @@ +// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \ +// RUN: -fsanitize=objc-cast -fsanitize-trap=objc-cast -emit-llvm %s -o - | FileCheck %s + +@interface NSFastEnumerationState +@end + +#define NSUInteger unsigned int + +@interface NSArray ++(NSArray*) arrayWithObjects: (id) first, ...; +- (NSUInteger) countByEnumeratingWithState:(NSFastEnumerationState *) state + objects:(id[]) buffer + count:(NSUInteger) len; +-(unsigned) count; +@end +@interface NSString +-(const char*) cString; +@end + +void receive_NSString(NSString*); + +void t0(void) { + NSArray *array = [NSArray arrayWithObjects: @"0", @"1", (void*)0]; + for (NSString *i in array) { + receive_NSString(i); + } +} + +// CHECK-LABEL: @t0 +// CHECK: call void @llvm.ubsantrap(i8 9) {{.*}}!dbg [[LOC:![0-9]+]] +// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}}) +// CHECK: [[MSG]] = distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer$Invalid Objective-C cast" diff --git a/clang/test/CodeGen/ubsan-trap-reason-load-invalid-value.c b/clang/test/CodeGen/ubsan-trap-reason-load-invalid-value.c new file mode 100644 index 0000000..4aad832 --- /dev/null +++ b/clang/test/CodeGen/ubsan-trap-reason-load-invalid-value.c @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \ +// RUN: -fsanitize=bool -fsanitize-trap=bool -emit-llvm %s -o - | FileCheck %s + +#include <stdbool.h> + +unsigned char bad_byte; + +bool load_invalid_value(void) { return *((bool *)&bad_byte); } + +// CHECK-LABEL: @load_invalid_value +// CHECK: call void @llvm.ubsantrap(i8 10) {{.*}}!dbg [[LOC:![0-9]+]] +// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}}) +// CHECK: [[MSG]] = distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer$Loaded an invalid or uninitialized value for the type" diff --git a/clang/test/CodeGen/ubsan-trap-reason-missing-return.cpp b/clang/test/CodeGen/ubsan-trap-reason-missing-return.cpp new file mode 100644 index 0000000..2818d9d --- /dev/null +++ b/clang/test/CodeGen/ubsan-trap-reason-missing-return.cpp @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \ +// RUN: -fsanitize=return -fsanitize-trap=return -emit-llvm %s -o - | FileCheck %s + +int missing_return(int x) { + if (x > 0) + return x; +} + +// CHECK-LABEL: @_Z14missing_return +// CHECK: call void @llvm.ubsantrap(i8 11) {{.*}}!dbg [[LOC:![0-9]+]] +// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}}) +// CHECK: [[MSG]] = distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer$Execution reached the end of a value-returning function without returning a value" diff --git a/clang/test/CodeGen/ubsan-trap-reason-mul-overflow.c b/clang/test/CodeGen/ubsan-trap-reason-mul-overflow.c new file mode 100644 index 0000000..cf9a0b4 --- /dev/null +++ b/clang/test/CodeGen/ubsan-trap-reason-mul-overflow.c @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \ +// RUN: -fsanitize=signed-integer-overflow -fsanitize-trap=signed-integer-overflow -emit-llvm %s -o - | FileCheck %s + +int mul_overflow(int a, int b) { return a * b; } + +// CHECK-LABEL: @mul_overflow +// CHECK: call void @llvm.ubsantrap(i8 12) {{.*}}!dbg [[LOC:![0-9]+]] +// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}}) +// CHECK: [[MSG]] = distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer$Integer multiplication overflowed" diff --git a/clang/test/CodeGen/ubsan-trap-reason-negate-overflow.c b/clang/test/CodeGen/ubsan-trap-reason-negate-overflow.c new file mode 100644 index 0000000..5534679 --- /dev/null +++ b/clang/test/CodeGen/ubsan-trap-reason-negate-overflow.c @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \ +// RUN: -fsanitize=signed-integer-overflow -fsanitize-trap=signed-integer-overflow -emit-llvm %s -o - | FileCheck %s + +int negate_overflow() { + int x; + return -x; +} + +// CHECK-LABEL: @negate_overflow +// CHECK: call void @llvm.ubsantrap(i8 13) {{.*}}!dbg [[LOC:![0-9]+]] +// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}}) +// CHECK: [[MSG]] = distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer$Integer negation overflowed" diff --git a/clang/test/CodeGen/ubsan-trap-reason-nonnull-arg.c b/clang/test/CodeGen/ubsan-trap-reason-nonnull-arg.c new file mode 100644 index 0000000..1f0f450 --- /dev/null +++ b/clang/test/CodeGen/ubsan-trap-reason-nonnull-arg.c @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \ +// RUN: -fsanitize=nonnull-attribute -fsanitize-trap=nonnull-attribute -emit-llvm %s -o - | FileCheck %s + +__attribute__((nonnull)) void nonnull_arg(int *p) { (void)p; } + +void trigger_nonnull_arg() { nonnull_arg(0); } + +// CHECK-LABEL: @nonnull_arg +// CHECK-LABEL: @trigger_nonnull_arg +// CHECK: call void @llvm.ubsantrap(i8 16) {{.*}}!dbg [[LOC:![0-9]+]] +// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}}) +// CHECK: [[MSG]] = distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer$Passing null pointer as an argument which is declared to never be null" diff --git a/clang/test/CodeGen/ubsan-trap-reason-nonnull-return.c b/clang/test/CodeGen/ubsan-trap-reason-nonnull-return.c new file mode 100644 index 0000000..1197b4d --- /dev/null +++ b/clang/test/CodeGen/ubsan-trap-reason-nonnull-return.c @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \ +// RUN: -fsanitize=returns-nonnull-attribute -fsanitize-trap=returns-nonnull-attribute -emit-llvm %s -o - | FileCheck %s + +__attribute__((returns_nonnull)) int *must_return_nonnull(int bad) { + if (bad) + return 0; + static int x = 1; + return &x; +} + +// CHECK-LABEL: @must_return_nonnull +// CHECK: call void @llvm.ubsantrap(i8 17) {{.*}}!dbg [[LOC:![0-9]+]] +// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}}) +// CHECK: [[MSG]] = distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer$Returning null pointer from a function which is declared to never return null" diff --git a/clang/test/CodeGen/ubsan-trap-reason-nullability-arg.c b/clang/test/CodeGen/ubsan-trap-reason-nullability-arg.c new file mode 100644 index 0000000..2bc71de --- /dev/null +++ b/clang/test/CodeGen/ubsan-trap-reason-nullability-arg.c @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \ +// RUN: -fsanitize=nullability-arg -fsanitize-trap=nullability-arg -emit-llvm %s -o - | FileCheck %s + +#include <stddef.h> + +int nullability_arg(int *_Nonnull p) { return *p; } + +int trigger_nullability_arg(void) { return nullability_arg(NULL); } + +// CHECK-LABEL: @nullability_arg +// CHECK-LABEL: @trigger_nullability_arg +// CHECK: call void @llvm.ubsantrap(i8 14) {{.*}}!dbg [[LOC:![0-9]+]] +// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}}) +// CHECK: [[MSG]] = distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer$Passing null as an argument which is annotated with _Nonnull" diff --git a/clang/test/CodeGen/ubsan-trap-reason-nullability-return.c b/clang/test/CodeGen/ubsan-trap-reason-nullability-return.c new file mode 100644 index 0000000..3d64c5a --- /dev/null +++ b/clang/test/CodeGen/ubsan-trap-reason-nullability-return.c @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \ +// RUN: -fsanitize=nullability-return -fsanitize-trap=nullability-return -emit-llvm %s -o - | FileCheck %s + +#include <stdbool.h> +#include <stddef.h> + +int *_Nonnull nullability_return(bool fail) { + if (fail) + return NULL; + + static int x = 0; + return &x; +} + +// CHECK-LABEL: @nullability_return +// CHECK: call void @llvm.ubsantrap(i8 15) {{.*}}!dbg [[LOC:![0-9]+]] +// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}}) +// CHECK: [[MSG]] = distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer$Returning null from a function with a return type annotated with _Nonnull" diff --git a/clang/test/CodeGen/ubsan-trap-reason-out-of-bounds.c b/clang/test/CodeGen/ubsan-trap-reason-out-of-bounds.c new file mode 100644 index 0000000..979886d --- /dev/null +++ b/clang/test/CodeGen/ubsan-trap-reason-out-of-bounds.c @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \ +// RUN: -fsanitize=array-bounds -fsanitize-trap=array-bounds -emit-llvm %s -o - | FileCheck %s + +int out_of_bounds() { + int a[1] = {0}; + return a[1]; +} + +// CHECK-LABEL: @out_of_bounds +// CHECK: call void @llvm.ubsantrap(i8 18) {{.*}}!dbg [[LOC:![0-9]+]] +// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}}) +// CHECK: [[MSG]] = distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer$Array index out of bounds" diff --git a/clang/test/CodeGen/ubsan-trap-reason-pointer-overflow.c b/clang/test/CodeGen/ubsan-trap-reason-pointer-overflow.c new file mode 100644 index 0000000..41cb487 --- /dev/null +++ b/clang/test/CodeGen/ubsan-trap-reason-pointer-overflow.c @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \ +// RUN: -fsanitize=pointer-overflow -fsanitize-trap=pointer-overflow -emit-llvm %s -o - | FileCheck %s + +#include <stddef.h> +#include <stdint.h> + +int *pointer_overflow(void) { + int buf[4]; + volatile size_t n = (SIZE_MAX / sizeof(int)) - 1; + return buf + n; +} + +// CHECK-LABEL: @pointer_overflow +// CHECK: call void @llvm.ubsantrap(i8 19) {{.*}}!dbg [[LOC:![0-9]+]] +// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}}) +// CHECK: [[MSG]] = distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer$Pointer arithmetic overflowed bounds" diff --git a/clang/test/CodeGen/ubsan-trap-reason-shift-out-of-bounds.c b/clang/test/CodeGen/ubsan-trap-reason-shift-out-of-bounds.c new file mode 100644 index 0000000..1a7465d --- /dev/null +++ b/clang/test/CodeGen/ubsan-trap-reason-shift-out-of-bounds.c @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \ +// RUN: -fsanitize=shift-base -fsanitize-trap=shift-base -emit-llvm %s -o - | FileCheck %s + +int shift_out_of_bounds(void) { + int sh = 32; + return 1 << sh; +} + +// CHECK-LABEL: @shift_out_of_bounds +// CHECK: call void @llvm.ubsantrap(i8 20) {{.*}}!dbg [[LOC:![0-9]+]] +// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}}) +// CHECK: [[MSG]] = distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer$Shift exponent is too large for the type" diff --git a/clang/test/CodeGen/ubsan-trap-reason-sub-overflow.c b/clang/test/CodeGen/ubsan-trap-reason-sub-overflow.c new file mode 100644 index 0000000..62aa7fc --- /dev/null +++ b/clang/test/CodeGen/ubsan-trap-reason-sub-overflow.c @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \ +// RUN: -fsanitize=signed-integer-overflow -fsanitize-trap=signed-integer-overflow -emit-llvm %s -o - | FileCheck %s + +int sub_overflow(int a, int b) { return a - b; } + +// CHECK-LABEL: @sub_overflow +// CHECK: call void @llvm.ubsantrap(i8 21) {{.*}}!dbg [[LOC:![0-9]+]] +// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}}) +// CHECK: [[MSG]] = distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer$Integer subtraction overflowed" diff --git a/clang/test/CodeGen/ubsan-trap-reason-type-mismatch.c b/clang/test/CodeGen/ubsan-trap-reason-type-mismatch.c new file mode 100644 index 0000000..802ec91 --- /dev/null +++ b/clang/test/CodeGen/ubsan-trap-reason-type-mismatch.c @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \ +// RUN: -fsanitize=alignment -fsanitize-trap=alignment -emit-llvm %s -o - | FileCheck %s + +int type_mismatch(int *p) { return *p; } + +// CHECK-LABEL: @type_mismatch +// CHECK: call void @llvm.ubsantrap(i8 22) {{.*}}!dbg [[LOC:![0-9]+]] +// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}}) +// CHECK: [[MSG]] = distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer$Type mismatch in operation" diff --git a/clang/test/CodeGen/ubsan-trap-reason-vla-bound-not-positive.c b/clang/test/CodeGen/ubsan-trap-reason-vla-bound-not-positive.c new file mode 100644 index 0000000..ad9c408 --- /dev/null +++ b/clang/test/CodeGen/ubsan-trap-reason-vla-bound-not-positive.c @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -triple arm64-apple-macosx14.0.0 -O0 -debug-info-kind=standalone -dwarf-version=5 \ +// RUN: -fsanitize=vla-bound -fsanitize-trap=vla-bound -emit-llvm %s -o - | FileCheck %s + +int n = 0; + +int vla_bound_not_positive(void) { + int a[n]; + return sizeof a; +} + +// CHECK-LABEL: @vla_bound_not_positive +// CHECK: call void @llvm.ubsantrap(i8 24) {{.*}}!dbg [[LOC:![0-9]+]] +// CHECK: [[LOC]] = !DILocation(line: 0, scope: [[MSG:![0-9]+]], {{.+}}) +// CHECK: [[MSG]] = distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer$Variable length array bound evaluates to non-positive value" diff --git a/clang/test/CodeGenCUDA/bf16.cu b/clang/test/CodeGenCUDA/bf16.cu index 1247438..701540e 100644 --- a/clang/test/CodeGenCUDA/bf16.cu +++ b/clang/test/CodeGenCUDA/bf16.cu @@ -35,8 +35,8 @@ __device__ __bf16 external_func( __bf16 in); // CHECK: .param .align 2 .b8 _Z9test_callDF16b_param_0[2] __device__ __bf16 test_call( __bf16 in) { // CHECK: ld.param.b16 %[[R:rs[0-9]+]], [_Z9test_callDF16b_param_0]; -// CHECK: st.param.b16 [param0], %[[R]]; // CHECK: .param .align 2 .b8 retval0[2]; +// CHECK: st.param.b16 [param0], %[[R]]; // CHECK: call.uni (retval0), _Z13external_funcDF16b, (param0); // CHECK: ld.param.b16 %[[RET:rs[0-9]+]], [retval0]; return external_func(in); diff --git a/clang/test/Driver/hip-binding.hip b/clang/test/Driver/hip-binding.hip index d8b3f1e..4d15f97 100644 --- a/clang/test/Driver/hip-binding.hip +++ b/clang/test/Driver/hip-binding.hip @@ -61,7 +61,7 @@ // MULTI-D-ONLY-NEXT: # "amdgcn-amd-amdhsa" - "clang", inputs: ["[[INPUT]]"], output: "[[GFX90a:.+]]" // MULTI-D-ONLY-NEXT: # "amdgcn-amd-amdhsa" - "AMDGCN::Linker", inputs: ["[[GFX90a]]"], output: "[[GFX90a_OUT:.+]]" // -// RUN: not %clang -### --target=x86_64-linux-gnu --offload-new-driver -ccc-print-bindings -nogpulib -nogpuinc \ +// RUN: not %clang -### --target=x86_64-linux-gnu --offload-new-driver -ccc-print-bindings -nogpulib -nogpuinc -emit-llvm \ // RUN: --no-gpu-bundle-output --offload-arch=gfx90a --offload-arch=gfx908 --offload-device-only -c -o %t %s 2>&1 \ // RUN: | FileCheck -check-prefix=MULTI-D-ONLY-NO-BUNDLE-O %s // MULTI-D-ONLY-NO-BUNDLE-O: error: cannot specify -o when generating multiple output files @@ -75,6 +75,13 @@ // MULTI-D-ONLY-O-NEXT: "amdgcn-amd-amdhsa" - "AMDGCN::Linker", inputs: ["[[GFX90A_OBJ]]"], output: "[[GFX90A:.+]]" // MULTI-D-ONLY-O-NEXT: "amdgcn-amd-amdhsa" - "AMDGCN::Linker", inputs: ["[[GFX908]]", "[[GFX90A]]"], output: "a.out" +// RUN: %clang -### --target=x86_64-linux-gnu --offload-new-driver -ccc-print-bindings -nogpulib -nogpuinc -emit-llvm \ +// RUN: --gpu-bundle-output --offload-arch=gfx90a --offload-arch=gfx908 --offload-device-only -c -o a.out %s 2>&1 \ +// RUN: | FileCheck -check-prefix=MULTI-D-ONLY-BC %s +// MULTI-D-ONLY-BC: "amdgcn-amd-amdhsa" - "clang", inputs: ["[[INPUT:.+]]"], output: "[[GFX908_BC:.+]]" +// MULTI-D-ONLY-BC-NEXT: "amdgcn-amd-amdhsa" - "clang", inputs: ["[[INPUT]]"], output: "[[GFX90A_BC:.+]]" +// MULTI-D-ONLY-BC-NEXT: "amdgcn-amd-amdhsa" - "AMDGCN::Linker", inputs: ["[[GFX908_BC]]", "[[GFX90A_BC]]"], output: "a.out" + // // Check to ensure that we can use '-fsyntax-only' for HIP output with the new // driver. diff --git a/clang/test/Driver/hipspv-link-static-library.hip b/clang/test/Driver/hipspv-link-static-library.hip new file mode 100644 index 0000000..03126ae --- /dev/null +++ b/clang/test/Driver/hipspv-link-static-library.hip @@ -0,0 +1,28 @@ +// Test HIPSPV static device library linking +// REQUIRES: system-linux +// UNSUPPORTED: system-windows + +// Create a dummy archive to test SDL linking +// RUN: rm -rf %t && mkdir %t +// RUN: touch %t/dummy.bc +// RUN: llvm-ar cr %t/libSDL.a %t/dummy.bc + +// Test that -l options are passed to llvm-link for --offload=spirv64 +// RUN: %clang -### --target=x86_64-linux-gnu --offload=spirv64 \ +// RUN: --hip-path=%S/Inputs/hipspv -nohipwrapperinc %s \ +// RUN: -L%t -lSDL \ +// RUN: 2>&1 | FileCheck -check-prefix=SDL-LINK %s + +// Test that .a files are properly unbundled and passed to llvm-link +// RUN: %clang -### --target=x86_64-linux-gnu --offload=spirv64 \ +// RUN: --hip-path=%S/Inputs/hipspv -nohipwrapperinc %s \ +// RUN: %t/libSDL.a \ +// RUN: 2>&1 | FileCheck -check-prefix=SDL-ARCHIVE %s + +// Verify that the input files are added before the SDL files in llvm-link command +// This tests the ordering fix to match HIPAMD behavior +// SDL-LINK: "{{.*}}clang-offload-bundler" "-unbundle" "-type=a" "-input={{.*}}libSDL.a" "-targets=hip-spirv64-unknown-unknown-unknown-generic" "-output=[[SDL_A:.*\.a]]" "-allow-missing-bundles" +// SDL-LINK: "{{.*}}llvm-link" "{{.*}}.bc" "[[SDL_A]]" "-o" + +// SDL-ARCHIVE: "{{.*}}clang-offload-bundler" "-unbundle" "-type=a" "-input={{.*}}libSDL.a" "-targets=hip-spirv64-unknown-unknown-unknown-generic" "-output=[[SDL_A:.*\.a]]" "-allow-missing-bundles" +// SDL-ARCHIVE: "{{.*}}llvm-link" "{{.*}}.bc" "[[SDL_A]]" "-o" diff --git a/clang/test/Headers/__cpuidex_conflict.c b/clang/test/Headers/__cpuidex_conflict.c index 8687a6a..49795c4 100644 --- a/clang/test/Headers/__cpuidex_conflict.c +++ b/clang/test/Headers/__cpuidex_conflict.c @@ -3,7 +3,10 @@ // RUN: %clang_cc1 %s -ffreestanding -fms-extensions -fms-compatibility \ // RUN: -fms-compatibility-version=19.00 -triple x86_64-pc-windows-msvc -emit-llvm -o - // %clang_cc1 %s -ffreestanding -triple x86_64-w64-windows-gnu -fms-extensions -emit-llvm -o - -// RUN: %clang_cc1 %s -ffreestanding -fopenmp -fopenmp-is-target-device -aux-triple x86_64-unknown-linux-gnu +// +// FIXME: See https://github.com/llvm/llvm-project/pull/121839 and +// FIXME: https://github.com/llvm/llvm-project/pull/126324 +// RUN: not %clang_cc1 %s -ffreestanding -fopenmp -fopenmp-is-target-device -aux-triple x86_64-unknown-linux-gnu typedef __SIZE_TYPE__ size_t; diff --git a/clang/test/Modules/Exposure-2.cppm b/clang/test/Modules/Exposure-2.cppm new file mode 100644 index 0000000..c09b739 --- /dev/null +++ b/clang/test/Modules/Exposure-2.cppm @@ -0,0 +1,27 @@ +// RUN: rm -rf %t +// RUN: mkdir -p %t +// RUN: split-file %s %t +// +// RUN: %clang_cc1 -std=c++20 -emit-reduced-module-interface %t/A.cppm -o %t/A.pcm +// RUN: %clang_cc1 -std=c++20 %t/A.cpp -fmodule-file=A=%t/A.pcm -fsyntax-only -verify + +//--- A.cppm +export module A; +export template <class T> +class C {}; + +export template <class T> +void foo() { + C<T> value; + (void) value; +} + +//--- A.cpp +// expected-no-diagnostics +import A; +namespace { +class Local {}; +} +void test() { + foo<Local>(); +} diff --git a/clang/test/Modules/Exposure.cppm b/clang/test/Modules/Exposure.cppm new file mode 100644 index 0000000..651a89e --- /dev/null +++ b/clang/test/Modules/Exposure.cppm @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 -std=c++20 %s -verify -fsyntax-only +export module M; +namespace { +class TULocalClass {}; +} + +template <typename T> +class Templ {}; + +class C { + TULocalClass foo() { return TULocalClass(); } // expected-warning {{TU local entity 'TULocalClass' is exposed}} +private: + TULocalClass Member; // expected-warning {{TU local entity 'TULocalClass' is exposed}} +}; + +static inline void its() {} +template<int> void g() { its(); } + +void f0() { + g<1>(); +} + +inline void f1() { + g<1>(); // expected-warning {{TU local entity 'g<1>' is exposed}} +} diff --git a/clang/test/Modules/specializations-lazy-load-parentmap-crash.cpp b/clang/test/Modules/specializations-lazy-load-parentmap-crash.cpp new file mode 100644 index 0000000..bd07ada --- /dev/null +++ b/clang/test/Modules/specializations-lazy-load-parentmap-crash.cpp @@ -0,0 +1,99 @@ +// RUN: rm -rf %t +// RUN: mkdir -p %t +// RUN: split-file --leading-lines %s %t +// +// Prepare the BMIs. +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -emit-module-interface -o %t/mod_a-part1.pcm %t/mod_a-part1.cppm +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -emit-module-interface -o %t/mod_a-part2.pcm %t/mod_a-part2.cppm +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -emit-module-interface -o %t/mod_a.pcm %t/mod_a.cppm -fmodule-file=mod_a:part2=%t/mod_a-part2.pcm -fmodule-file=mod_a:part1=%t/mod_a-part1.pcm +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -emit-module-interface -o %t/mod_b.pcm %t/mod_b.cppm -fmodule-file=mod_a:part2=%t/mod_a-part2.pcm -fmodule-file=mod_a=%t/mod_a.pcm -fmodule-file=mod_a:part1=%t/mod_a-part1.pcm + +// Below are two examples to trigger the construction of the parent map (which is necessary to trigger the bug this regression test is for). +// Using ArrayBoundV2 checker: +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -analyze -analyzer-checker=security,alpha.security -analyzer-output=text %t/test-array-bound-v2.cpp -fmodule-file=mod_a:part2=%t/mod_a-part2.pcm -fmodule-file=mod_a=%t/mod_a.pcm -fmodule-file=mod_a:part1=%t/mod_a-part1.pcm -fmodule-file=mod_b=%t/mod_b.pcm +// Using a sanitized build: +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fsanitize=unsigned-integer-overflow -fsanitize-undefined-ignore-overflow-pattern=all -emit-llvm -o %t/ignored %t/test-sanitized-build.cpp -fmodule-file=mod_a:part2=%t/mod_a-part2.pcm -fmodule-file=mod_a=%t/mod_a.pcm -fmodule-file=mod_a:part1=%t/mod_a-part1.pcm -fmodule-file=mod_b=%t/mod_b.pcm + +//--- mod_a-part1.cppm +module; +namespace mod_a { +template <int> struct Important; +} + +namespace mod_a { +Important<0>& instantiate1(); +} // namespace mod_a +export module mod_a:part1; + +export namespace mod_a { +using ::mod_a::instantiate1; +} + +//--- mod_a-part2.cppm +module; +namespace mod_a { +template <int> struct Important; +} + +namespace mod_a { +template <int N> Important<N>& instantiate2(); +namespace part2InternalInstantiations { +// During the construction of the parent map, we iterate over ClassTemplateDecl::specializations() for 'Important'. +// After GH119333, the following instantiations get loaded between the call to spec_begin() and spec_end(). +// This used to invalidate the begin iterator returned by spec_begin() by the time the end iterator is returned. +// This is a regression test for that. +Important<1> fn1(); +Important<2> fn2(); +Important<3> fn3(); +Important<4> fn4(); +Important<5> fn5(); +Important<6> fn6(); +Important<7> fn7(); +Important<8> fn8(); +Important<9> fn9(); +Important<10> fn10(); +Important<11> fn11(); +} +} // namespace mod_a +export module mod_a:part2; + +export namespace mod_a { +using ::mod_a::instantiate2; +} + +//--- mod_a.cppm +export module mod_a; +export import :part1; +export import :part2; + +//--- mod_b.cppm +export module mod_b; +import mod_a; + +void a() { + mod_a::instantiate1(); + mod_a::instantiate2<42>(); +} + +//--- test-array-bound-v2.cpp +import mod_b; + +extern void someFunc(char* first, char* last); +void triggerParentMapContextCreationThroughArrayBoundV2() { + // This code currently causes the ArrayBoundV2 checker to create the ParentMapContext. + // Once it detects an access to buf[100], the checker looks through the parents to find '&' operator. + // (this is needed since taking the address of past-the-end pointer is allowed by the checker) + char buf[100]; + someFunc(&buf[0], &buf[100]); +} + +//--- test-sanitized-build.cpp +import mod_b; + +extern void some(); +void triggerParentMapContextCreationThroughSanitizedBuild(unsigned i) { + // This code currently causes UBSan to create the ParentMapContext. + // UBSan currently excludes the pattern below to avoid noise, and it relies on ParentMapContext to detect it. + while (i--) + some(); +} diff --git a/clang/test/Preprocessor/builtin_aux_info.cpp b/clang/test/Preprocessor/builtin_aux_info.cpp new file mode 100644 index 0000000..60c8c6c --- /dev/null +++ b/clang/test/Preprocessor/builtin_aux_info.cpp @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -fopenmp -triple=spirv64 -fopenmp-is-target-device \ +// RUN: -aux-triple x86_64-linux-unknown -E %s | FileCheck -implicit-check-not=BAD %s + +// RUN: %clang_cc1 -fopenmp -triple=nvptx64 -fopenmp-is-target-device \ +// RUN: -aux-triple x86_64-linux-unknown -E %s | FileCheck -implicit-check-not=BAD %s + +// RUN: %clang_cc1 -fopenmp -triple=amdgcn-amd-amdhsa -fopenmp-is-target-device \ +// RUN: -aux-triple x86_64-linux-unknown -E %s | FileCheck -implicit-check-not=BAD %s + +// RUN: %clang_cc1 -fopenmp -triple=aarch64 -fopenmp-is-target-device \ +// RUN: -aux-triple x86_64-linux-unknown -E %s | FileCheck -implicit-check-not=BAD %s + +// CHECK: GOOD +#if __has_builtin(__builtin_ia32_pause) + BAD +#else + GOOD +#endif diff --git a/clang/test/Preprocessor/riscv-target-features-cv.c b/clang/test/Preprocessor/riscv-target-features-cv.c new file mode 100644 index 0000000..a424a34 --- /dev/null +++ b/clang/test/Preprocessor/riscv-target-features-cv.c @@ -0,0 +1,60 @@ +// RUN: %clang --target=riscv32-unknown-linux-gnu -march=rv32i -E -dM %s \ +// RUN: -o - | FileCheck %s +// RUN: %clang --target=riscv64-unknown-linux-gnu -march=rv64i -E -dM %s \ +// RUN: -o - | FileCheck %s + +// CHECK-NOT: __riscv_xcvalu {{.*$}} +// CHECK-NOT: __riscv_xcvbi {{.*$}} +// CHECK-NOT: __riscv_xcvbitmanip {{.*$}} +// CHECK-NOT: __riscv_xcvelw {{.*$}} +// CHECK-NOT: __riscv_xcvmac {{.*$}} +// CHECK-NOT: __riscv_xcvmem {{.*$}} +// CHECK-NOT: __riscv_xcvsimd {{.*$}} + +// RUN: %clang --target=riscv32-unknown-linux-gnu \ +// RUN: -march=rv32ixcvalu -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-XCVALU-EXT %s +// RUN: %clang --target=riscv64-unknown-linux-gnu \ +// RUN: -march=rv64ixcvalu -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-XCVALU-EXT %s +// CHECK-XCVALU-EXT: __riscv_xcvalu 1000000{{$}} + +// RUN: %clang --target=riscv32-unknown-linux-gnu \ +// RUN: -march=rv32ixcvbi -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-XCVBI-EXT %s +// RUN: %clang --target=riscv64-unknown-linux-gnu \ +// RUN: -march=rv64ixcvbi -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-XCVBI-EXT %s +// CHECK-XCVBI-EXT: __riscv_xcvbi 1000000{{$}} + +// RUN: %clang --target=riscv32-unknown-linux-gnu \ +// RUN: -march=rv32ixcvbitmanip -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-XCVBITMANIP-EXT %s +// RUN: %clang --target=riscv64-unknown-linux-gnu \ +// RUN: -march=rv64ixcvbitmanip -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-XCVBITMANIP-EXT %s +// CHECK-XCVBITMANIP-EXT: __riscv_xcvbitmanip 1000000{{$}} + +// RUN: %clang --target=riscv32-unknown-linux-gnu \ +// RUN: -march=rv32ixcvmac -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-XCVMAC-EXT %s +// RUN: %clang --target=riscv64-unknown-linux-gnu \ +// RUN: -march=rv64ixcvmac -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-XCVMAC-EXT %s +// CHECK-XCVMAC-EXT: __riscv_xcvmac 1000000{{$}} + +// RUN: %clang --target=riscv32-unknown-linux-gnu \ +// RUN: -march=rv32ixcvmem -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-XCVMEM-EXT %s +// RUN: %clang --target=riscv64-unknown-linux-gnu \ +// RUN: -march=rv64ixcvmem -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-XCVMEM-EXT %s +// CHECK-XCVMEM-EXT: __riscv_xcvmem 1000000{{$}} + +// RUN: %clang --target=riscv32-unknown-linux-gnu \ +// RUN: -march=rv32ixcvsimd -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-XCVSIMD-EXT %s +// RUN: %clang --target=riscv64-unknown-linux-gnu \ +// RUN: -march=rv64ixcvsimd -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-XCVSIMD-EXT %s +// CHECK-XCVSIMD-EXT: __riscv_xcvsimd 1000000{{$}} diff --git a/clang/test/Preprocessor/riscv-target-features-sifive.c b/clang/test/Preprocessor/riscv-target-features-sifive.c index e4c0387..1c49b55 100644 --- a/clang/test/Preprocessor/riscv-target-features-sifive.c +++ b/clang/test/Preprocessor/riscv-target-features-sifive.c @@ -1,3 +1,91 @@ +// RUN: %clang --target=riscv32-unknown-linux-gnu -march=rv32i -E -dM %s \ +// RUN: -o - | FileCheck %s +// RUN: %clang --target=riscv64-unknown-linux-gnu -march=rv64i -E -dM %s \ +// RUN: -o - | FileCheck %s + +// CHECK-NOT: __riscv_xsfcease {{.*$}} +// CHECK-NOT: __riscv_xsfvcp {{.*$}} +// CHECK-NOT: __riscv_xsfvfnrclipxfqf {{.*$}} +// CHECK-NOT: __riscv_xsfvfwmaccqqq {{.*$}} +// CHECK-NOT: __riscv_xsfqmaccdod {{.*$}} +// CHECK-NOT: __riscv_xsfvqmaccqoq {{.*$}} +// CHECK-NOT: __riscv_xsifivecdiscarddlone {{.*$}} +// CHECK-NOT: __riscv_xsifivecflushdlone {{.*$}} +// CHECK-NOT: __riscv_xsfmm128t {{.*$}} +// CHECK-NOT: __riscv_xsfmm16t {{.*$}} +// CHECK-NOT: __riscv_xsfmm32a8i {{.*$}} +// CHECK-NOT: __riscv_xsfmm32a8f {{.*$}} +// CHECK-NOT: __riscv_xsfmm32a16f {{.*$}} +// CHECK-NOT: __riscv_xsfmm32a32f {{.*$}} +// CHECK-NOT: __riscv_xsfmm32a32t {{.*$}} +// CHECK-NOT: __riscv_xsfmm64a64f {{.*$}} +// CHECK-NOT: __riscv_xsfmm64t {{.*$}} +// CHECK-NOT: __riscv_xsfmmbase {{.*$}} + +// RUN: %clang --target=riscv32-unknown-linux-gnu \ +// RUN: -march=rv32ixsfcease -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-XSFCEASE-EXT %s +// RUN: %clang --target=riscv64-unknown-linux-gnu \ +// RUN: -march=rv64ixsfcease -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-XSFCEASE-EXT %s +// CHECK-XSFCEASE-EXT: __riscv_xsfcease 1000000{{$}} + +// RUN: %clang --target=riscv32-unknown-linux-gnu \ +// RUN: -march=rv32ixsfvcp -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-XSFVCP-EXT %s +// RUN: %clang --target=riscv64-unknown-linux-gnu \ +// RUN: -march=rv64ixsfvcp -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-XSFVCP-EXT %s +// CHECK-XSFVCP-EXT: __riscv_xsfvcp 1000000{{$}} + +// RUN: %clang --target=riscv32-unknown-linux-gnu \ +// RUN: -march=rv32ixsfvfnrclipxfqf -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-XSFVFNRCLIPXFQF-EXT %s +// RUN: %clang --target=riscv64-unknown-linux-gnu \ +// RUN: -march=rv64ixsfvfnrclipxfqf -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-XSFVFNRCLIPXFQF-EXT %s +// CHECK-XSFVFNRCLIPXFQF-EXT: __riscv_xsfvfnrclipxfqf 1000000{{$}} + +// RUN: %clang --target=riscv32-unknown-linux-gnu \ +// RUN: -march=rv32ixsfvfwmaccqqq -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-XSFVFWMACCQQQ-EXT %s +// RUN: %clang --target=riscv64-unknown-linux-gnu \ +// RUN: -march=rv64ixsfvfwmaccqqq -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-XSFVFWMACCQQQ-EXT %s +// CHECK-XSFVFWMACCQQQ-EXT: __riscv_xsfvfwmaccqqq 1000000{{$}} + +// RUN: %clang --target=riscv32-unknown-linux-gnu \ +// RUN: -march=rv32ixsfvqmaccdod -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-XSFVQMACCDOD-EXT %s +// RUN: %clang --target=riscv64-unknown-linux-gnu \ +// RUN: -march=rv64ixsfvqmaccdod -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-XSFVQMACCDOD-EXT %s +// CHECK-XSFVQMACCDOD-EXT: __riscv_xsfvqmaccdod 1000000{{$}} + +// RUN: %clang --target=riscv32-unknown-linux-gnu \ +// RUN: -march=rv32ixsfvqmaccqoq -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-XSFVQMACCQOQ-EXT %s +// RUN: %clang --target=riscv64-unknown-linux-gnu \ +// RUN: -march=rv64ixsfvqmaccqoq -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-XSFVQMACCQOQ-EXT %s +// CHECK-XSFVQMACCQOQ-EXT: __riscv_xsfvqmaccqoq 1000000{{$}} + +// RUN: %clang --target=riscv32-unknown-linux-gnu \ +// RUN: -march=rv32ixsifivecdiscarddlone -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-XSIFIVECDISCARDDLONE-EXT %s +// RUN: %clang --target=riscv64-unknown-linux-gnu \ +// RUN: -march=rv64ixsifivecdiscarddlone -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-XSIFIVECDISCARDDLONE-EXT %s +// CHECK-XSIFIVECDISCARDDLONE-EXT: __riscv_xsifivecdiscarddlone 1000000{{$}} + +// RUN: %clang --target=riscv32-unknown-linux-gnu \ +// RUN: -march=rv32ixsifivecflushdlone -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-XSIFIVECFLUSHDLONE-EXT %s +// RUN: %clang --target=riscv64-unknown-linux-gnu \ +// RUN: -march=rv64ixsifivecflushdlone -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-XSIFIVECFLUSHDLONE-EXT %s +// CHECK-XSIFIVECFLUSHDLONE-EXT: __riscv_xsifivecflushdlone 1000000{{$}} + // RUN: %clang --target=riscv32 \ // RUN: -march=rv32i_zve32x_xsfmm128t -E -dM %s \ // RUN: -o - | FileCheck --check-prefix=CHECK-XSFMM128T %s diff --git a/clang/test/Preprocessor/riscv-target-features-thead.c b/clang/test/Preprocessor/riscv-target-features-thead.c new file mode 100644 index 0000000..9d27d9a --- /dev/null +++ b/clang/test/Preprocessor/riscv-target-features-thead.c @@ -0,0 +1,104 @@ +// RUN: %clang --target=riscv32-unknown-linux-gnu -march=rv32i -E -dM %s \ +// RUN: -o - | FileCheck %s +// RUN: %clang --target=riscv64-unknown-linux-gnu -march=rv64i -E -dM %s \ +// RUN: -o - | FileCheck %s + +// CHECK-NOT: __riscv_xtheadba {{.*$}} +// CHECK-NOT: __riscv_xtheadbb {{.*$}} +// CHECK-NOT: __riscv_xtheadbs {{.*$}} +// CHECK-NOT: __riscv_xtheadcmo {{.*$}} +// CHECK-NOT: __riscv_xtheadcondmov {{.*$}} +// CHECK-NOT: __riscv_xtheadfmemidx {{.*$}} +// CHECK-NOT: __riscv_xtheadmac {{.*$}} +// CHECK-NOT: __riscv_xtheadmemidx {{.*$}} +// CHECK-NOT: __riscv_xtheadmempair {{.*$}} +// CHECK-NOT: __riscv_xtheadsync {{.*$}} +// CHECK-NOT: __riscv_xtheadvdot {{.*$}} + +// RUN: %clang --target=riscv32-unknown-linux-gnu \ +// RUN: -march=rv32ixtheadba -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-XTHEADBA-EXT %s +// RUN: %clang --target=riscv64-unknown-linux-gnu \ +// RUN: -march=rv64ixtheadba -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-XTHEADBA-EXT %s +// CHECK-XTHEADBA-EXT: __riscv_xtheadba 1000000{{$}} + +// RUN: %clang --target=riscv32-unknown-linux-gnu \ +// RUN: -march=rv32ixtheadbb -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-XTHEADBB-EXT %s +// RUN: %clang --target=riscv64-unknown-linux-gnu \ +// RUN: -march=rv64ixtheadbb -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-XTHEADBB-EXT %s +// CHECK-XTHEADBB-EXT: __riscv_xtheadbb 1000000{{$}} + +// RUN: %clang --target=riscv32-unknown-linux-gnu \ +// RUN: -march=rv32ixtheadbs -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-XTHEADBS-EXT %s +// RUN: %clang --target=riscv64-unknown-linux-gnu \ +// RUN: -march=rv64ixtheadbs -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-XTHEADBS-EXT %s +// CHECK-XTHEADBS-EXT: __riscv_xtheadbs 1000000{{$}} + +// RUN: %clang --target=riscv32-unknown-linux-gnu \ +// RUN: -march=rv32ixtheadcmo -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-XTHEADCMO-EXT %s +// RUN: %clang --target=riscv64-unknown-linux-gnu \ +// RUN: -march=rv64ixtheadcmo -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-XTHEADCMO-EXT %s +// CHECK-XTHEADCMO-EXT: __riscv_xtheadcmo 1000000{{$}} + +// RUN: %clang --target=riscv32-unknown-linux-gnu \ +// RUN: -march=rv32ixtheadcondmov -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-XTHEADCONDMOV-EXT %s +// RUN: %clang --target=riscv64-unknown-linux-gnu \ +// RUN: -march=rv64ixtheadcondmov -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-XTHEADCONDMOV-EXT %s +// CHECK-XTHEADCONDMOV-EXT: __riscv_xtheadcondmov 1000000{{$}} + +// RUN: %clang --target=riscv32-unknown-linux-gnu \ +// RUN: -march=rv32ixtheadfmemidx -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-XTHEADFMEMIDX-EXT %s +// RUN: %clang --target=riscv64-unknown-linux-gnu \ +// RUN: -march=rv64ixtheadfmemidx -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-XTHEADFMEMIDX-EXT %s +// CHECK-XTHEADFMEMIDX-EXT: __riscv_xtheadfmemidx 1000000{{$}} + +// RUN: %clang --target=riscv32-unknown-linux-gnu \ +// RUN: -march=rv32ixtheadmac -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-XTHEADMAC-EXT %s +// RUN: %clang --target=riscv64-unknown-linux-gnu \ +// RUN: -march=rv64ixtheadmac -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-XTHEADMAC-EXT %s +// CHECK-XTHEADMAC-EXT: __riscv_xtheadmac 1000000{{$}} + +// RUN: %clang --target=riscv32-unknown-linux-gnu \ +// RUN: -march=rv32ixtheadmemidx -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-XTHEADMEMIDX-EXT %s +// RUN: %clang --target=riscv64-unknown-linux-gnu \ +// RUN: -march=rv64ixtheadmemidx -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-XTHEADMEMIDX-EXT %s +// CHECK-XTHEADMEMIDX-EXT: __riscv_xtheadmemidx 1000000{{$}} + +// RUN: %clang --target=riscv32-unknown-linux-gnu \ +// RUN: -march=rv32ixtheadmempair -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-XTHEADMEMPAIR-EXT %s +// RUN: %clang --target=riscv64-unknown-linux-gnu \ +// RUN: -march=rv64ixtheadmempair -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-XTHEADMEMPAIR-EXT %s +// CHECK-XTHEADMEMPAIR-EXT: __riscv_xtheadmempair 1000000{{$}} + +// RUN: %clang --target=riscv32-unknown-linux-gnu \ +// RUN: -march=rv32ixtheadsync -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-XTHEADSYNC-EXT %s +// RUN: %clang --target=riscv64-unknown-linux-gnu \ +// RUN: -march=rv64ixtheadsync -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-XTHEADSYNC-EXT %s +// CHECK-XTHEADSYNC-EXT: __riscv_xtheadsync 1000000{{$}} + +// RUN: %clang --target=riscv32-unknown-linux-gnu \ +// RUN: -march=rv32ixtheadvdot -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-XTHEADVDOT-EXT %s +// RUN: %clang --target=riscv64-unknown-linux-gnu \ +// RUN: -march=rv64ixtheadvdot -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-XTHEADVDOT-EXT %s +// CHECK-XTHEADVDOT-EXT: __riscv_xtheadvdot 1000000{{$}} diff --git a/clang/test/Preprocessor/riscv-target-features.c b/clang/test/Preprocessor/riscv-target-features.c index 86085c2..864d782 100644 --- a/clang/test/Preprocessor/riscv-target-features.c +++ b/clang/test/Preprocessor/riscv-target-features.c @@ -64,32 +64,6 @@ // CHECK-NOT: __riscv_v_intrinsic {{.*$}} // CHECK-NOT: __riscv_v_min_vlen {{.*$}} // CHECK-NOT: __riscv_vector {{.*$}} -// CHECK-NOT: __riscv_xcvalu {{.*$}} -// CHECK-NOT: __riscv_xcvbi {{.*$}} -// CHECK-NOT: __riscv_xcvbitmanip {{.*$}} -// CHECK-NOT: __riscv_xcvelw {{.*$}} -// CHECK-NOT: __riscv_xcvmac {{.*$}} -// CHECK-NOT: __riscv_xcvmem {{.*$}} -// CHECK-NOT: __riscv_xcvsimd {{.*$}} -// CHECK-NOT: __riscv_xsfcease {{.*$}} -// CHECK-NOT: __riscv_xsfvcp {{.*$}} -// CHECK-NOT: __riscv_xsfvfnrclipxfqf {{.*$}} -// CHECK-NOT: __riscv_xsfvfwmaccqqq {{.*$}} -// CHECK-NOT: __riscv_xsfqmaccdod {{.*$}} -// CHECK-NOT: __riscv_xsfvqmaccqoq {{.*$}} -// CHECK-NOT: __riscv_xsifivecdiscarddlone {{.*$}} -// CHECK-NOT: __riscv_xsifivecflushdlone {{.*$}} -// CHECK-NOT: __riscv_xtheadba {{.*$}} -// CHECK-NOT: __riscv_xtheadbb {{.*$}} -// CHECK-NOT: __riscv_xtheadbs {{.*$}} -// CHECK-NOT: __riscv_xtheadcmo {{.*$}} -// CHECK-NOT: __riscv_xtheadcondmov {{.*$}} -// CHECK-NOT: __riscv_xtheadfmemidx {{.*$}} -// CHECK-NOT: __riscv_xtheadmac {{.*$}} -// CHECK-NOT: __riscv_xtheadmemidx {{.*$}} -// CHECK-NOT: __riscv_xtheadmempair {{.*$}} -// CHECK-NOT: __riscv_xtheadsync {{.*$}} -// CHECK-NOT: __riscv_xtheadvdot {{.*$}} // CHECK-NOT: __riscv_xventanacondops {{.*$}} // CHECK-NOT: __riscv_za128rs {{.*$}} // CHECK-NOT: __riscv_za64rs {{.*$}} @@ -569,198 +543,6 @@ // CHECK-V-EXT: __riscv_vector 1 // RUN: %clang --target=riscv32-unknown-linux-gnu \ -// RUN: -march=rv32ixcvalu -E -dM %s \ -// RUN: -o - | FileCheck --check-prefix=CHECK-XCVALU-EXT %s -// RUN: %clang --target=riscv64-unknown-linux-gnu \ -// RUN: -march=rv64ixcvalu -E -dM %s \ -// RUN: -o - | FileCheck --check-prefix=CHECK-XCVALU-EXT %s -// CHECK-XCVALU-EXT: __riscv_xcvalu 1000000{{$}} - -// RUN: %clang --target=riscv32-unknown-linux-gnu \ -// RUN: -march=rv32ixcvbi -E -dM %s \ -// RUN: -o - | FileCheck --check-prefix=CHECK-XCVBI-EXT %s -// RUN: %clang --target=riscv64-unknown-linux-gnu \ -// RUN: -march=rv64ixcvbi -E -dM %s \ -// RUN: -o - | FileCheck --check-prefix=CHECK-XCVBI-EXT %s -// CHECK-XCVBI-EXT: __riscv_xcvbi 1000000{{$}} - -// RUN: %clang --target=riscv32-unknown-linux-gnu \ -// RUN: -march=rv32ixcvbitmanip -E -dM %s \ -// RUN: -o - | FileCheck --check-prefix=CHECK-XCVBITMANIP-EXT %s -// RUN: %clang --target=riscv64-unknown-linux-gnu \ -// RUN: -march=rv64ixcvbitmanip -E -dM %s \ -// RUN: -o - | FileCheck --check-prefix=CHECK-XCVBITMANIP-EXT %s -// CHECK-XCVBITMANIP-EXT: __riscv_xcvbitmanip 1000000{{$}} - -// RUN: %clang --target=riscv32-unknown-linux-gnu \ -// RUN: -march=rv32ixcvmac -E -dM %s \ -// RUN: -o - | FileCheck --check-prefix=CHECK-XCVMAC-EXT %s -// RUN: %clang --target=riscv64-unknown-linux-gnu \ -// RUN: -march=rv64ixcvmac -E -dM %s \ -// RUN: -o - | FileCheck --check-prefix=CHECK-XCVMAC-EXT %s -// CHECK-XCVMAC-EXT: __riscv_xcvmac 1000000{{$}} - -// RUN: %clang --target=riscv32-unknown-linux-gnu \ -// RUN: -march=rv32ixcvsimd -E -dM %s \ -// RUN: -o - | FileCheck --check-prefix=CHECK-XCVSIMD-EXT %s -// RUN: %clang --target=riscv64-unknown-linux-gnu \ -// RUN: -march=rv64ixcvsimd -E -dM %s \ -// RUN: -o - | FileCheck --check-prefix=CHECK-XCVSIMD-EXT %s -// CHECK-XCVSIMD-EXT: __riscv_xcvsimd 1000000{{$}} - -// RUN: %clang --target=riscv32-unknown-linux-gnu \ -// RUN: -march=rv32ixsfcease -E -dM %s \ -// RUN: -o - | FileCheck --check-prefix=CHECK-XSFCEASE-EXT %s -// RUN: %clang --target=riscv64-unknown-linux-gnu \ -// RUN: -march=rv64ixsfcease -E -dM %s \ -// RUN: -o - | FileCheck --check-prefix=CHECK-XSFCEASE-EXT %s -// CHECK-XSFCEASE-EXT: __riscv_xsfcease 1000000{{$}} - -// RUN: %clang --target=riscv32-unknown-linux-gnu \ -// RUN: -march=rv32ixsfvcp -E -dM %s \ -// RUN: -o - | FileCheck --check-prefix=CHECK-XSFVCP-EXT %s -// RUN: %clang --target=riscv64-unknown-linux-gnu \ -// RUN: -march=rv64ixsfvcp -E -dM %s \ -// RUN: -o - | FileCheck --check-prefix=CHECK-XSFVCP-EXT %s -// CHECK-XSFVCP-EXT: __riscv_xsfvcp 1000000{{$}} - -// RUN: %clang --target=riscv32-unknown-linux-gnu \ -// RUN: -march=rv32ixsfvfnrclipxfqf -E -dM %s \ -// RUN: -o - | FileCheck --check-prefix=CHECK-XSFVFNRCLIPXFQF-EXT %s -// RUN: %clang --target=riscv64-unknown-linux-gnu \ -// RUN: -march=rv64ixsfvfnrclipxfqf -E -dM %s \ -// RUN: -o - | FileCheck --check-prefix=CHECK-XSFVFNRCLIPXFQF-EXT %s -// CHECK-XSFVFNRCLIPXFQF-EXT: __riscv_xsfvfnrclipxfqf 1000000{{$}} - -// RUN: %clang --target=riscv32-unknown-linux-gnu \ -// RUN: -march=rv32ixsfvfwmaccqqq -E -dM %s \ -// RUN: -o - | FileCheck --check-prefix=CHECK-XSFVFWMACCQQQ-EXT %s -// RUN: %clang --target=riscv64-unknown-linux-gnu \ -// RUN: -march=rv64ixsfvfwmaccqqq -E -dM %s \ -// RUN: -o - | FileCheck --check-prefix=CHECK-XSFVFWMACCQQQ-EXT %s -// CHECK-XSFVFWMACCQQQ-EXT: __riscv_xsfvfwmaccqqq 1000000{{$}} - -// RUN: %clang --target=riscv32-unknown-linux-gnu \ -// RUN: -march=rv32ixsfvqmaccdod -E -dM %s \ -// RUN: -o - | FileCheck --check-prefix=CHECK-XSFVQMACCDOD-EXT %s -// RUN: %clang --target=riscv64-unknown-linux-gnu \ -// RUN: -march=rv64ixsfvqmaccdod -E -dM %s \ -// RUN: -o - | FileCheck --check-prefix=CHECK-XSFVQMACCDOD-EXT %s -// CHECK-XSFVQMACCDOD-EXT: __riscv_xsfvqmaccdod 1000000{{$}} - -// RUN: %clang --target=riscv32-unknown-linux-gnu \ -// RUN: -march=rv32ixsfvqmaccqoq -E -dM %s \ -// RUN: -o - | FileCheck --check-prefix=CHECK-XSFVQMACCQOQ-EXT %s -// RUN: %clang --target=riscv64-unknown-linux-gnu \ -// RUN: -march=rv64ixsfvqmaccqoq -E -dM %s \ -// RUN: -o - | FileCheck --check-prefix=CHECK-XSFVQMACCQOQ-EXT %s -// CHECK-XSFVQMACCQOQ-EXT: __riscv_xsfvqmaccqoq 1000000{{$}} - -// RUN: %clang --target=riscv32-unknown-linux-gnu \ -// RUN: -march=rv32ixsifivecdiscarddlone -E -dM %s \ -// RUN: -o - | FileCheck --check-prefix=CHECK-XSIFIVECDISCARDDLONE-EXT %s -// RUN: %clang --target=riscv64-unknown-linux-gnu \ -// RUN: -march=rv64ixsifivecdiscarddlone -E -dM %s \ -// RUN: -o - | FileCheck --check-prefix=CHECK-XSIFIVECDISCARDDLONE-EXT %s -// CHECK-XSIFIVECDISCARDDLONE-EXT: __riscv_xsifivecdiscarddlone 1000000{{$}} - -// RUN: %clang --target=riscv32-unknown-linux-gnu \ -// RUN: -march=rv32ixsifivecflushdlone -E -dM %s \ -// RUN: -o - | FileCheck --check-prefix=CHECK-XSIFIVECFLUSHDLONE-EXT %s -// RUN: %clang --target=riscv64-unknown-linux-gnu \ -// RUN: -march=rv64ixsifivecflushdlone -E -dM %s \ -// RUN: -o - | FileCheck --check-prefix=CHECK-XSIFIVECFLUSHDLONE-EXT %s -// CHECK-XSIFIVECFLUSHDLONE-EXT: __riscv_xsifivecflushdlone 1000000{{$}} - -// RUN: %clang --target=riscv32-unknown-linux-gnu \ -// RUN: -march=rv32ixtheadba -E -dM %s \ -// RUN: -o - | FileCheck --check-prefix=CHECK-XTHEADBA-EXT %s -// RUN: %clang --target=riscv64-unknown-linux-gnu \ -// RUN: -march=rv64ixtheadba -E -dM %s \ -// RUN: -o - | FileCheck --check-prefix=CHECK-XTHEADBA-EXT %s -// CHECK-XTHEADBA-EXT: __riscv_xtheadba 1000000{{$}} - -// RUN: %clang --target=riscv32-unknown-linux-gnu \ -// RUN: -march=rv32ixtheadbb -E -dM %s \ -// RUN: -o - | FileCheck --check-prefix=CHECK-XTHEADBB-EXT %s -// RUN: %clang --target=riscv64-unknown-linux-gnu \ -// RUN: -march=rv64ixtheadbb -E -dM %s \ -// RUN: -o - | FileCheck --check-prefix=CHECK-XTHEADBB-EXT %s -// CHECK-XTHEADBB-EXT: __riscv_xtheadbb 1000000{{$}} - -// RUN: %clang --target=riscv32-unknown-linux-gnu \ -// RUN: -march=rv32ixtheadbs -E -dM %s \ -// RUN: -o - | FileCheck --check-prefix=CHECK-XTHEADBS-EXT %s -// RUN: %clang --target=riscv64-unknown-linux-gnu \ -// RUN: -march=rv64ixtheadbs -E -dM %s \ -// RUN: -o - | FileCheck --check-prefix=CHECK-XTHEADBS-EXT %s -// CHECK-XTHEADBS-EXT: __riscv_xtheadbs 1000000{{$}} - -// RUN: %clang --target=riscv32-unknown-linux-gnu \ -// RUN: -march=rv32ixtheadcmo -E -dM %s \ -// RUN: -o - | FileCheck --check-prefix=CHECK-XTHEADCMO-EXT %s -// RUN: %clang --target=riscv64-unknown-linux-gnu \ -// RUN: -march=rv64ixtheadcmo -E -dM %s \ -// RUN: -o - | FileCheck --check-prefix=CHECK-XTHEADCMO-EXT %s -// CHECK-XTHEADCMO-EXT: __riscv_xtheadcmo 1000000{{$}} - -// RUN: %clang --target=riscv32-unknown-linux-gnu \ -// RUN: -march=rv32ixtheadcondmov -E -dM %s \ -// RUN: -o - | FileCheck --check-prefix=CHECK-XTHEADCONDMOV-EXT %s -// RUN: %clang --target=riscv64-unknown-linux-gnu \ -// RUN: -march=rv64ixtheadcondmov -E -dM %s \ -// RUN: -o - | FileCheck --check-prefix=CHECK-XTHEADCONDMOV-EXT %s -// CHECK-XTHEADCONDMOV-EXT: __riscv_xtheadcondmov 1000000{{$}} - -// RUN: %clang --target=riscv32-unknown-linux-gnu \ -// RUN: -march=rv32ixtheadfmemidx -E -dM %s \ -// RUN: -o - | FileCheck --check-prefix=CHECK-XTHEADFMEMIDX-EXT %s -// RUN: %clang --target=riscv64-unknown-linux-gnu \ -// RUN: -march=rv64ixtheadfmemidx -E -dM %s \ -// RUN: -o - | FileCheck --check-prefix=CHECK-XTHEADFMEMIDX-EXT %s -// CHECK-XTHEADFMEMIDX-EXT: __riscv_xtheadfmemidx 1000000{{$}} - -// RUN: %clang --target=riscv32-unknown-linux-gnu \ -// RUN: -march=rv32ixtheadmac -E -dM %s \ -// RUN: -o - | FileCheck --check-prefix=CHECK-XTHEADMAC-EXT %s -// RUN: %clang --target=riscv64-unknown-linux-gnu \ -// RUN: -march=rv64ixtheadmac -E -dM %s \ -// RUN: -o - | FileCheck --check-prefix=CHECK-XTHEADMAC-EXT %s -// CHECK-XTHEADMAC-EXT: __riscv_xtheadmac 1000000{{$}} - -// RUN: %clang --target=riscv32-unknown-linux-gnu \ -// RUN: -march=rv32ixtheadmemidx -E -dM %s \ -// RUN: -o - | FileCheck --check-prefix=CHECK-XTHEADMEMIDX-EXT %s -// RUN: %clang --target=riscv64-unknown-linux-gnu \ -// RUN: -march=rv64ixtheadmemidx -E -dM %s \ -// RUN: -o - | FileCheck --check-prefix=CHECK-XTHEADMEMIDX-EXT %s -// CHECK-XTHEADMEMIDX-EXT: __riscv_xtheadmemidx 1000000{{$}} - -// RUN: %clang --target=riscv32-unknown-linux-gnu \ -// RUN: -march=rv32ixtheadmempair -E -dM %s \ -// RUN: -o - | FileCheck --check-prefix=CHECK-XTHEADMEMPAIR-EXT %s -// RUN: %clang --target=riscv64-unknown-linux-gnu \ -// RUN: -march=rv64ixtheadmempair -E -dM %s \ -// RUN: -o - | FileCheck --check-prefix=CHECK-XTHEADMEMPAIR-EXT %s -// CHECK-XTHEADMEMPAIR-EXT: __riscv_xtheadmempair 1000000{{$}} - -// RUN: %clang --target=riscv32-unknown-linux-gnu \ -// RUN: -march=rv32ixtheadsync -E -dM %s \ -// RUN: -o - | FileCheck --check-prefix=CHECK-XTHEADSYNC-EXT %s -// RUN: %clang --target=riscv64-unknown-linux-gnu \ -// RUN: -march=rv64ixtheadsync -E -dM %s \ -// RUN: -o - | FileCheck --check-prefix=CHECK-XTHEADSYNC-EXT %s -// CHECK-XTHEADSYNC-EXT: __riscv_xtheadsync 1000000{{$}} - -// RUN: %clang --target=riscv32-unknown-linux-gnu \ -// RUN: -march=rv32ixtheadvdot -E -dM %s \ -// RUN: -o - | FileCheck --check-prefix=CHECK-XTHEADVDOT-EXT %s -// RUN: %clang --target=riscv64-unknown-linux-gnu \ -// RUN: -march=rv64ixtheadvdot -E -dM %s \ -// RUN: -o - | FileCheck --check-prefix=CHECK-XTHEADVDOT-EXT %s -// CHECK-XTHEADVDOT-EXT: __riscv_xtheadvdot 1000000{{$}} - -// RUN: %clang --target=riscv32-unknown-linux-gnu \ // RUN: -march=rv32ixventanacondops -E -dM %s \ // RUN: -o - | FileCheck --check-prefix=CHECK-XVENTANACONDOPS-EXT %s // RUN: %clang --target=riscv64-unknown-linux-gnu \ diff --git a/clang/test/Sema/attr-nonstring.c b/clang/test/Sema/attr-nonstring.c index 3838aa3..fe7b6d2 100644 --- a/clang/test/Sema/attr-nonstring.c +++ b/clang/test/Sema/attr-nonstring.c @@ -229,3 +229,11 @@ struct Outer o2[] = { } } }; + +// The attribute also works with a pointer type, not just an array type. +__attribute__((nonstring)) char *ptr1; +__attribute__((nonstring)) const unsigned char *ptr2; +struct GH150951 { + __attribute__((nonstring)) char *ptr1; + __attribute__((nonstring)) const unsigned char *ptr2; +}; diff --git a/clang/test/SemaCXX/cxx2b-deducing-this.cpp b/clang/test/SemaCXX/cxx2b-deducing-this.cpp index 2253cbb..fcbe0f6 100644 --- a/clang/test/SemaCXX/cxx2b-deducing-this.cpp +++ b/clang/test/SemaCXX/cxx2b-deducing-this.cpp @@ -1357,3 +1357,35 @@ void Bar(this int) { // expected-note {{candidate function}} } } + +namespace GH147046_regression { + +template <typename z> struct ai { + ai(z::ah); +}; + +template <typename z> struct ak { + template <typename am> void an(am, z); + template <typename am> static void an(am, ai<z>); +}; +template <typename> struct ao {}; + +template <typename ap> +auto ar(ao<ap> at) -> decltype(ak<ap>::an(at, 0)); +// expected-note@-1 {{candidate template ignored: substitution failure [with ap = GH147046_regression::ay]: no matching function for call to 'an'}} + +class aw; +struct ax { + typedef int ah; +}; +struct ay { + typedef aw ah; +}; + +ao<ay> az ; +ai<ax> bd(0); +void f() { + ar(az); // expected-error {{no matching function for call to 'ar'}} +} + +} diff --git a/clang/test/SemaCXX/warn-unused-result.cpp b/clang/test/SemaCXX/warn-unused-result.cpp index fe7d5ea..447654e 100644 --- a/clang/test/SemaCXX/warn-unused-result.cpp +++ b/clang/test/SemaCXX/warn-unused-result.cpp @@ -365,6 +365,31 @@ void id_print_name() { } } // namespace GH117975 +namespace inheritance { +// Test that [[nodiscard]] is not inherited by derived class types, +// but is inherited by member functions +struct [[nodiscard]] E { + [[nodiscard]] explicit E(int); + explicit E(const char*); + [[nodiscard]] int f(); +}; +struct F : E { + using E::E; +}; +E e(); +F f(); +void test() { + e(); // expected-warning {{ignoring return value of type 'E' declared with 'nodiscard' attribute}} + f(); // no warning: derived class type does not inherit the attribute + E(1); // expected-warning {{ignoring temporary created by a constructor declared with 'nodiscard' attribute}} + E("x"); // expected-warning {{ignoring temporary of type 'E' declared with 'nodiscard' attribute}} + F(1); // no warning: inherited constructor does not inherit the attribute either + F("x"); // no warning + e().f(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + f().f(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} +} +} // namespace inheritance + namespace BuildStringOnClangScope { [[clang::warn_unused_result("Discarded result")]] @@ -381,4 +406,4 @@ void doGccThings() { makeGccTrue(); // expected-warning {{ignoring return value of function declared with 'gnu::warn_unused_result' attribute}} } -} +} // namespace BuildStringOnClangScope diff --git a/clang/test/SemaObjC/attr-nodiscard.m b/clang/test/SemaObjC/attr-nodiscard.m new file mode 100644 index 0000000..6d04665 --- /dev/null +++ b/clang/test/SemaObjC/attr-nodiscard.m @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +struct [[nodiscard]] expected {}; + +typedef struct expected E; + +@interface INTF +- (int) a [[nodiscard]]; ++ (int) b [[nodiscard]]; +- (struct expected) c; ++ (struct expected) d; +- (E) e; ++ (E) f; +- (void) g [[nodiscard]]; // expected-warning {{attribute 'nodiscard' cannot be applied to Objective-C method without return value}} +@end + +void foo(INTF *a) { + [a a]; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + [INTF b]; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + [a c]; // expected-warning {{ignoring return value of type 'expected' declared with 'nodiscard' attribute}} + [INTF d]; // expected-warning {{ignoring return value of type 'expected' declared with 'nodiscard' attribute}} + [a e]; // expected-warning {{ignoring return value of type 'expected' declared with 'nodiscard' attribute}} + [INTF f]; // expected-warning {{ignoring return value of type 'expected' declared with 'nodiscard' attribute}} + [a g]; +} diff --git a/clang/test/SemaObjCXX/attr-nodiscard.mm b/clang/test/SemaObjCXX/attr-nodiscard.mm new file mode 100644 index 0000000..e1eefb7 --- /dev/null +++ b/clang/test/SemaObjCXX/attr-nodiscard.mm @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +template<class T> +struct [[nodiscard]] expected {}; + +using E = expected<int>; + +@interface INTF +- (int) a [[nodiscard]]; ++ (int) b [[nodiscard]]; +- (expected<int>) c; ++ (expected<int>) d; +- (E) e; ++ (E) f; +- (void) g [[nodiscard]]; // expected-warning {{attribute 'nodiscard' cannot be applied to Objective-C method without return value}} +@end + +void foo(INTF *a) { + [a a]; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + [INTF b]; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + [a c]; // expected-warning {{ignoring return value of type 'expected<int>' declared with 'nodiscard' attribute}} + [INTF d]; // expected-warning {{ignoring return value of type 'expected<int>' declared with 'nodiscard' attribute}} + [a e]; // expected-warning {{ignoring return value of type 'expected<int>' declared with 'nodiscard' attribute}} + [INTF f]; // expected-warning {{ignoring return value of type 'expected<int>' declared with 'nodiscard' attribute}} + [a g]; +} diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index 553d980..9c5aa11 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -12114,7 +12114,12 @@ TEST_F(FormatTest, UnderstandsFunctionRefQualification) { "void b() const &;\n"; verifyFormat(Prefix + "int *x;", Prefix + "int* x;", DerivePointerAlignment); - verifyGoogleFormat("MACRO(int*, std::function<void() &&>);"); + constexpr StringRef Code("MACRO(int*, std::function<void() &&>);"); + verifyFormat(Code, DerivePointerAlignment); + + auto Style = getGoogleStyle(); + Style.DerivePointerAlignment = true; + verifyFormat(Code, Style); } TEST_F(FormatTest, PointerAlignmentFallback) { |