diff options
Diffstat (limited to 'clang')
20 files changed, 1088 insertions, 361 deletions
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/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/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/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/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/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/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/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/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/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/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/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) { |