diff --git a/clang/include/clang/Basic/Diagnostic.h b/clang/include/clang/Basic/Diagnostic.h index 9cc94c38e60d17..304207779c0f18 100644 --- a/clang/include/clang/Basic/Diagnostic.h +++ b/clang/include/clang/Basic/Diagnostic.h @@ -1010,6 +1010,11 @@ class DiagnosticsEngine : public RefCountedBase { /// RAII class that determines when any errors have occurred /// between the time the instance was created and the time it was /// queried. +/// +/// Note that you almost certainly do not want to use this. It's usually +/// meaningless to ask whether a particular scope triggered an error message, +/// because error messages outside that scope can mark things invalid (or cause +/// us to reach an error limit), which can suppress errors within that scope. class DiagnosticErrorTrap { DiagnosticsEngine &Diag; unsigned NumErrors; diff --git a/clang/include/clang/Sema/Scope.h b/clang/include/clang/Sema/Scope.h index 169ca175eed228..9b8f1415a1e378 100644 --- a/clang/include/clang/Sema/Scope.h +++ b/clang/include/clang/Sema/Scope.h @@ -325,8 +325,10 @@ class Scope { DeclContext *getEntity() const { return Entity; } void setEntity(DeclContext *E) { Entity = E; } - bool hasErrorOccurred() const { return ErrorTrap.hasErrorOccurred(); } - + /// Determine whether any unrecoverable errors have occurred within this + /// scope. Note that this may return false even if the scope contains invalid + /// declarations or statements, if the errors for those invalid constructs + /// were suppressed because some prior invalid construct was referenced. bool hasUnrecoverableErrorOccurred() const { return ErrorTrap.hasUnrecoverableErrorOccurred(); } diff --git a/clang/include/clang/Sema/ScopeInfo.h b/clang/include/clang/Sema/ScopeInfo.h index 3c4847a2932cda..f0f9cb9e40ae01 100644 --- a/clang/include/clang/Sema/ScopeInfo.h +++ b/clang/include/clang/Sema/ScopeInfo.h @@ -174,9 +174,11 @@ class FunctionScopeInfo { /// First SEH '__try' statement in the current function. SourceLocation FirstSEHTryLoc; +private: /// Used to determine if errors occurred in this function or block. DiagnosticErrorTrap ErrorTrap; +public: /// A SwitchStmt, along with a flag indicating if its list of case statements /// is incomplete (because we dropped an invalid one while parsing). using SwitchInfo = llvm::PointerIntPair; @@ -375,6 +377,17 @@ class FunctionScopeInfo { virtual ~FunctionScopeInfo(); + /// Determine whether an unrecoverable error has occurred within this + /// function. Note that this may return false even if the function body is + /// invalid, because the errors may be suppressed if they're caused by prior + /// invalid declarations. + /// + /// FIXME: Migrate the caller of this to use containsErrors() instead once + /// it's ready. + bool hasUnrecoverableErrorOccurred() const { + return ErrorTrap.hasUnrecoverableErrorOccurred(); + } + /// Record that a weak object was accessed. /// /// Part of the implementation of -Wrepeated-use-of-weak. diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 8f914ec451f6cc..8df78a5a7acaa3 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -8293,6 +8293,12 @@ class Sema final { /// We are rewriting a comparison operator in terms of an operator<=>. RewritingOperatorAsSpaceship, + /// We are initializing a structured binding. + InitializingStructuredBinding, + + /// We are marking a class as __dllexport. + MarkingClassDllexported, + /// Added for Template instantiation observation. /// Memoization means we are _not_ instantiating a template because /// it is already instantiated (but we entered a context where we diff --git a/clang/lib/Driver/ToolChains/ROCm.h b/clang/lib/Driver/ToolChains/ROCm.h index 9f5fa451472bc2..779e2e133becd1 100644 --- a/clang/lib/Driver/ToolChains/ROCm.h +++ b/clang/lib/Driver/ToolChains/ROCm.h @@ -10,9 +10,14 @@ #define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ROCM_H #include "clang/Basic/Cuda.h" +#include "clang/Basic/LLVM.h" +#include "clang/Driver/Driver.h" #include "clang/Driver/Options.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Option/ArgList.h" namespace clang { namespace driver { diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp index 42615d27e92c96..3a86a8d05c49bd 100644 --- a/clang/lib/Frontend/FrontendActions.cpp +++ b/clang/lib/Frontend/FrontendActions.cpp @@ -434,6 +434,10 @@ class DefaultTemplateInstCallback : public TemplateInstantiationCallback { return "RequirementInstantiation"; case CodeSynthesisContext::NestedRequirementConstraintsCheck: return "NestedRequirementConstraintsCheck"; + case CodeSynthesisContext::InitializingStructuredBinding: + return "InitializingStructuredBinding"; + case CodeSynthesisContext::MarkingClassDllexported: + return "MarkingClassDllexported"; } return ""; } diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index bf7ada348878d7..d7947777977ae4 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -3369,7 +3369,6 @@ ExprResult Parser::ParseRequiresExpression() { ParsedAttributes FirstArgAttrs(getAttrFactory()); SourceLocation EllipsisLoc; llvm::SmallVector LocalParameters; - DiagnosticErrorTrap Trap(Diags); ParseParameterDeclarationClause(DeclaratorContext::RequiresExprContext, FirstArgAttrs, LocalParameters, EllipsisLoc); @@ -3377,8 +3376,6 @@ ExprResult Parser::ParseRequiresExpression() { Diag(EllipsisLoc, diag::err_requires_expr_parameter_list_ellipsis); for (auto &ParamInfo : LocalParameters) LocalParameterDecls.push_back(cast(ParamInfo.Param)); - if (Trap.hasErrorOccurred()) - SkipUntil(tok::r_paren, StopBeforeMatch); } Parens.consumeClose(); } diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index ffe2e4d4d56ad0..49fbde85cdfbc2 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -1952,7 +1952,7 @@ void Sema::PopCompoundScope() { /// Determine whether any errors occurred within this function/method/ /// block. bool Sema::hasAnyUnrecoverableErrorsInThisFunction() const { - return getCurFunction()->ErrorTrap.hasUnrecoverableErrorOccurred(); + return getCurFunction()->hasUnrecoverableErrorOccurred(); } void Sema::setFunctionHasBranchIntoScope() { diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 025b09de0ad1ce..401aea355c411a 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -12317,7 +12317,7 @@ void Sema::ActOnInitializerError(Decl *D) { BD->setInvalidDecl(); // Auto types are meaningless if we can't make sense of the initializer. - if (ParsingInitForAutoVars.count(D)) { + if (VD->getType()->isUndeducedType()) { D->setInvalidDecl(); return; } @@ -14385,7 +14385,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, // If any errors have occurred, clear out any temporaries that may have // been leftover. This ensures that these temporaries won't be picked up for // deletion in some later function. - if (getDiagnostics().hasErrorOccurred() || + if (getDiagnostics().hasUncompilableErrorOccurred() || getDiagnostics().getSuppressAllDiagnostics()) { DiscardCleanupsInEvaluationContext(); } @@ -14441,7 +14441,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, // If any errors have occurred, clear out any temporaries that may have // been leftover. This ensures that these temporaries won't be picked up for // deletion in some later function. - if (getDiagnostics().hasErrorOccurred()) { + if (getDiagnostics().hasUncompilableErrorOccurred()) { DiscardCleanupsInEvaluationContext(); } diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index ed12b6cacdbe09..09d381a5a1ba3d 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -1101,16 +1101,17 @@ static QualType getTupleLikeElementType(Sema &S, SourceLocation Loc, } namespace { -struct BindingDiagnosticTrap { +struct InitializingBinding { Sema &S; - DiagnosticErrorTrap Trap; - BindingDecl *BD; - - BindingDiagnosticTrap(Sema &S, BindingDecl *BD) - : S(S), Trap(S.Diags), BD(BD) {} - ~BindingDiagnosticTrap() { - if (Trap.hasErrorOccurred()) - S.Diag(BD->getLocation(), diag::note_in_binding_decl_init) << BD; + InitializingBinding(Sema &S, BindingDecl *BD) : S(S) { + Sema::CodeSynthesisContext Ctx; + Ctx.Kind = Sema::CodeSynthesisContext::InitializingStructuredBinding; + Ctx.PointOfInstantiation = BD->getLocation(); + Ctx.Entity = BD; + S.pushCodeSynthesisContext(Ctx); + } + ~InitializingBinding() { + S.popCodeSynthesisContext(); } }; } @@ -1159,7 +1160,7 @@ static bool checkTupleLikeDecomposition(Sema &S, unsigned I = 0; for (auto *B : Bindings) { - BindingDiagnosticTrap Trap(S, B); + InitializingBinding InitContext(S, B); SourceLocation Loc = B->getLocation(); ExprResult E = S.BuildDeclRefExpr(Src, DecompType, VK_LValue, Loc); @@ -5797,6 +5798,23 @@ static void ReferenceDllExportedMembers(Sema &S, CXXRecordDecl *Class) { // declaration. return; + // Add a context note to explain how we got to any diagnostics produced below. + struct MarkingClassDllexported { + Sema &S; + MarkingClassDllexported(Sema &S, CXXRecordDecl *Class, + SourceLocation AttrLoc) + : S(S) { + Sema::CodeSynthesisContext Ctx; + Ctx.Kind = Sema::CodeSynthesisContext::MarkingClassDllexported; + Ctx.PointOfInstantiation = AttrLoc; + Ctx.Entity = Class; + S.pushCodeSynthesisContext(Ctx); + } + ~MarkingClassDllexported() { + S.popCodeSynthesisContext(); + } + } MarkingDllexportedContext(S, Class, ClassAttr->getLocation()); + if (S.Context.getTargetInfo().getTriple().isWindowsGNUEnvironment()) S.MarkVTableUsed(Class->getLocation(), Class, true); @@ -5832,13 +5850,7 @@ static void ReferenceDllExportedMembers(Sema &S, CXXRecordDecl *Class) { // defaulted methods, and the copy and move assignment operators. The // latter are exported even if they are trivial, because the address of // an operator can be taken and should compare equal across libraries. - DiagnosticErrorTrap Trap(S.Diags); S.MarkFunctionReferenced(Class->getLocation(), MD); - if (Trap.hasErrorOccurred()) { - S.Diag(ClassAttr->getLocation(), diag::note_due_to_dllexported_class) - << Class << !S.getLangOpts().CPlusPlus11; - break; - } // There is no later point when we will see the definition of this // function, so pass it to the consumer now. diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index c22af86d57aa63..b3d04e40b5e9eb 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -7595,13 +7595,13 @@ ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl, // a difference in ARC, but outside of ARC the resulting block literal // follows the normal lifetime rules for block literals instead of being // autoreleased. - DiagnosticErrorTrap Trap(Diags); PushExpressionEvaluationContext( ExpressionEvaluationContext::PotentiallyEvaluated); ExprResult BlockExp = BuildBlockForLambdaConversion( Exp.get()->getExprLoc(), Exp.get()->getExprLoc(), Method, Exp.get()); PopExpressionEvaluationContext(); + // FIXME: This note should be produced by a CodeSynthesisContext. if (BlockExp.isInvalid()) Diag(Exp.get()->getExprLoc(), diag::note_lambda_to_block_conv); return BlockExp; diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index 8d32fc094494fc..9d5672cff00afa 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -2127,18 +2127,22 @@ StmtResult Sema::ActOnCXXForRangeStmt(Scope *S, SourceLocation ForLoc, return StmtError(); } + // This function is responsible for attaching an initializer to LoopVar. We + // must call ActOnInitializerError if we fail to do so. Decl *LoopVar = DS->getSingleDecl(); if (LoopVar->isInvalidDecl() || !Range || DiagnoseUnexpandedParameterPack(Range, UPPC_Expression)) { - LoopVar->setInvalidDecl(); + ActOnInitializerError(LoopVar); return StmtError(); } // Build the coroutine state immediately and not later during template // instantiation if (!CoawaitLoc.isInvalid()) { - if (!ActOnCoroutineBodyStart(S, CoawaitLoc, "co_await")) + if (!ActOnCoroutineBodyStart(S, CoawaitLoc, "co_await")) { + ActOnInitializerError(LoopVar); return StmtError(); + } } // Build auto && __range = range-init @@ -2150,7 +2154,7 @@ StmtResult Sema::ActOnCXXForRangeStmt(Scope *S, SourceLocation ForLoc, std::string("__range") + DepthStr); if (FinishForRangeVarDecl(*this, RangeVar, Range, RangeLoc, diag::err_for_range_deduction_failure)) { - LoopVar->setInvalidDecl(); + ActOnInitializerError(LoopVar); return StmtError(); } @@ -2159,14 +2163,20 @@ StmtResult Sema::ActOnCXXForRangeStmt(Scope *S, SourceLocation ForLoc, BuildDeclaratorGroup(MutableArrayRef((Decl **)&RangeVar, 1)); StmtResult RangeDecl = ActOnDeclStmt(RangeGroup, RangeLoc, RangeLoc); if (RangeDecl.isInvalid()) { - LoopVar->setInvalidDecl(); + ActOnInitializerError(LoopVar); return StmtError(); } - return BuildCXXForRangeStmt( + StmtResult R = BuildCXXForRangeStmt( ForLoc, CoawaitLoc, InitStmt, ColonLoc, RangeDecl.get(), /*BeginStmt=*/nullptr, /*EndStmt=*/nullptr, /*Cond=*/nullptr, /*Inc=*/nullptr, DS, RParenLoc, Kind); + if (R.isInvalid()) { + ActOnInitializerError(LoopVar); + return StmtError(); + } + + return R; } /// Create the initialization, compare, and increment steps for @@ -2349,22 +2359,6 @@ static StmtResult RebuildForRangeWithDereference(Sema &SemaRef, Scope *S, AdjustedRange.get(), RParenLoc, Sema::BFRK_Rebuild); } -namespace { -/// RAII object to automatically invalidate a declaration if an error occurs. -struct InvalidateOnErrorScope { - InvalidateOnErrorScope(Sema &SemaRef, Decl *D, bool Enabled) - : Trap(SemaRef.Diags), D(D), Enabled(Enabled) {} - ~InvalidateOnErrorScope() { - if (Enabled && Trap.hasErrorOccurred()) - D->setInvalidDecl(); - } - - DiagnosticErrorTrap Trap; - Decl *D; - bool Enabled; -}; -} - /// BuildCXXForRangeStmt - Build or instantiate a C++11 for-range statement. StmtResult Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc, Stmt *InitStmt, @@ -2391,11 +2385,6 @@ StmtResult Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, DeclStmt *LoopVarDS = cast(LoopVarDecl); VarDecl *LoopVar = cast(LoopVarDS->getSingleDecl()); - // If we hit any errors, mark the loop variable as invalid if its type - // contains 'auto'. - InvalidateOnErrorScope Invalidate(*this, LoopVar, - LoopVar->getType()->isUndeducedType()); - StmtResult BeginDeclStmt = Begin; StmtResult EndDeclStmt = End; ExprResult NotEqExpr = Cond, IncrExpr = Inc; @@ -2434,11 +2423,8 @@ StmtResult Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, QualType RangeType = Range->getType(); if (RequireCompleteType(RangeLoc, RangeType, - diag::err_for_range_incomplete_type)) { - if (LoopVar->getType()->isUndeducedType()) - LoopVar->setInvalidDecl(); + diag::err_for_range_incomplete_type)) return StmtError(); - } // Build auto __begin = begin-expr, __end = end-expr. // Divide by 2, since the variables are in the inner scope (loop body). diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 0cb50b3ea36874..a27b87e3c80181 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -215,6 +215,8 @@ bool Sema::CodeSynthesisContext::isInstantiationRecord() const { case ParameterMappingSubstitution: case ConstraintNormalization: case RewritingOperatorAsSpaceship: + case InitializingStructuredBinding: + case MarkingClassDllexported: return false; // This function should never be called when Kind's value is Memoization. @@ -760,6 +762,18 @@ void Sema::PrintInstantiationStack() { diag::note_rewriting_operator_as_spaceship); break; + case CodeSynthesisContext::InitializingStructuredBinding: + Diags.Report(Active->PointOfInstantiation, + diag::note_in_binding_decl_init) + << cast(Active->Entity); + break; + + case CodeSynthesisContext::MarkingClassDllexported: + Diags.Report(Active->PointOfInstantiation, + diag::note_due_to_dllexported_class) + << cast(Active->Entity) << !getLangOpts().CPlusPlus11; + break; + case CodeSynthesisContext::Memoization: break; @@ -861,6 +875,8 @@ Optional Sema::isSFINAEContext() const { case CodeSynthesisContext::DeclaringImplicitEqualityComparison: case CodeSynthesisContext::DefiningSynthesizedFunction: case CodeSynthesisContext::RewritingOperatorAsSpaceship: + case CodeSynthesisContext::InitializingStructuredBinding: + case CodeSynthesisContext::MarkingClassDllexported: // This happens in a context unrelated to template instantiation, so // there is no SFINAE. return None; diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 519d9128037db7..b4aa234a3934f2 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -5879,10 +5879,11 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, if (!Result) { if (isa(D)) { // UsingShadowDecls can instantiate to nothing because of using hiding. - } else if (Diags.hasErrorOccurred()) { - // We've already complained about something, so most likely this - // declaration failed to instantiate. There's no point in complaining - // further, since this is normal in invalid code. + } else if (Diags.hasUncompilableErrorOccurred()) { + // We've already complained about some ill-formed code, so most likely + // this declaration failed to instantiate. There's no point in + // complaining further, since this is normal in invalid code. + // FIXME: Use more fine-grained 'invalid' tracking for this. } else if (IsBeingInstantiated) { // The class in which this member exists is currently being // instantiated, and we haven't gotten around to instantiating this diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index bfbdfbf14379df..ff9d4d610660a1 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -8086,8 +8086,12 @@ TreeTransform::TransformCXXForRangeStmt(CXXForRangeStmt *S) { Cond.get(), Inc.get(), LoopVar.get(), S->getRParenLoc()); - if (NewStmt.isInvalid()) + if (NewStmt.isInvalid() && LoopVar.get() != S->getLoopVarStmt()) { + // Might not have attached any initializer to the loop variable. + getSema().ActOnInitializerError( + cast(LoopVar.get())->getSingleDecl()); return StmtError(); + } } StmtResult Body = getDerived().TransformStmt(S->getBody()); diff --git a/clang/test/Parser/cxx2a-concepts-requires-expr.cpp b/clang/test/Parser/cxx2a-concepts-requires-expr.cpp index fa42b0633850b7..d1a31b4f93ef16 100644 --- a/clang/test/Parser/cxx2a-concepts-requires-expr.cpp +++ b/clang/test/Parser/cxx2a-concepts-requires-expr.cpp @@ -43,6 +43,7 @@ bool r14 = requires (int (*f)(int)) { requires true; }; bool r15 = requires (10) { requires true; }; // expected-error@-1 {{expected parameter declarator}} +// expected-error@-2 {{expected ')'}} expected-note@-2 {{to match}} bool r16 = requires (auto x) { requires true; }; // expected-error@-1 {{'auto' not allowed in requires expression parameter}} diff --git a/clang/test/SemaCXX/cxx11-crashes.cpp b/clang/test/SemaCXX/cxx11-crashes.cpp index 19205db85b6c6b..d60782df35f45e 100644 --- a/clang/test/SemaCXX/cxx11-crashes.cpp +++ b/clang/test/SemaCXX/cxx11-crashes.cpp @@ -71,6 +71,7 @@ namespace b6981007 { // We used to attempt to evaluate the initializer of this variable, // and crash because it has an undeduced type. const int &n(x); + constexpr int k = sizeof(x); } } } diff --git a/clang/test/SemaCXX/for-range-crash.cpp b/clang/test/SemaCXX/for-range-crash.cpp index 21637264a2bf6c..766f34e50ed430 100644 --- a/clang/test/SemaCXX/for-range-crash.cpp +++ b/clang/test/SemaCXX/for-range-crash.cpp @@ -1,5 +1,10 @@ // RUN: %clang_cc1 -fsyntax-only -verify -std=c++17 %s +// Ensure that we don't crash if errors are suppressed by an error limit. +// RUN: not %clang_cc1 -fsyntax-only -std=c++17 -ferror-limit=1 %s + +error e; // expected-error {{unknown type name}} + template class Bar { Bar *variables_to_modify; @@ -8,3 +13,18 @@ class Bar { delete c; } }; + +void foo() { + int a; + struct X; // expected-note {{forward declaration}} + for (X x // expected-error {{incomplete type}} + : a) { // expected-error {{range expression of type 'int'}} + constexpr int n = sizeof(x); + } + + struct S { int x, y; }; + for (S [x, y] // expected-error {{must be 'auto'}} + : a) { // expected-error {{range expression}} + typename decltype(x)::a b; + } +} diff --git a/flang/include/flang/Evaluate/integer.h b/flang/include/flang/Evaluate/integer.h index ecefbc45b2cdcd..6b91cb250c98ed 100644 --- a/flang/include/flang/Evaluate/integer.h +++ b/flang/include/flang/Evaluate/integer.h @@ -805,9 +805,13 @@ class Integer { if (Part ypart{y.LEPart(k)}) { BigPart xy{xpart}; xy *= ypart; - // && to < (2 * parts) was added to avoid GCC < 8 build failure - // on -Werror=array-bounds - for (int to{ j + k }; xy != 0 && to < (2 * parts); ++to) { +#if defined __GNUC__ && __GNUC__ < 8 + // && to < (2 * parts) was added to avoid GCC < 8 build failure on + // -Werror=array-bounds. This can be removed if -Werror is disable. + for (int to{j + k}; xy != 0 && to < (2 * parts); ++to) { +#else + for (int to{j + k}; xy != 0; ++to) { +#endif xy += product[to]; product[to] = xy & partMask; xy >>= partBits; diff --git a/flang/lib/Decimal/big-radix-floating-point.h b/flang/lib/Decimal/big-radix-floating-point.h index 67f0b46ab213aa..18626e2b55df43 100644 --- a/flang/lib/Decimal/big-radix-floating-point.h +++ b/flang/lib/Decimal/big-radix-floating-point.h @@ -179,10 +179,13 @@ template class BigRadixFloatingPointNumber { if (remove >= digits_) { digits_ = 0; } else if (remove > 0) { +#if defined __GNUC__ && __GNUC__ < 8 // (&& j + remove < maxDigits) was added to avoid GCC < 8 build failure - // on -Werror=array-bounds - for (int j{ 0 }; j + remove < digits_ && (j + remove < maxDigits); - ++j) { + // on -Werror=array-bounds. This can be removed if -Werror is disable. + for (int j{0}; j + remove < digits_ && (j + remove < maxDigits); ++j) { +#else + for (int j{0}; j + remove < digits_; ++j) { +#endif digit_[j] = digit_[j + remove]; } digits_ -= remove; diff --git a/lld/MachO/CMakeLists.txt b/lld/MachO/CMakeLists.txt index a4dc69ea35934c..6fe356f5158949 100644 --- a/lld/MachO/CMakeLists.txt +++ b/lld/MachO/CMakeLists.txt @@ -24,6 +24,7 @@ add_lld_library(lldMachO2 Object Option Support + TextAPI LINK_LIBS lldCommon diff --git a/llvm/include/llvm/BinaryFormat/XCOFF.h b/llvm/include/llvm/BinaryFormat/XCOFF.h index 3a35b822643bbe..0b0040c418a855 100644 --- a/llvm/include/llvm/BinaryFormat/XCOFF.h +++ b/llvm/include/llvm/BinaryFormat/XCOFF.h @@ -27,6 +27,7 @@ constexpr size_t FileNamePadSize = 6; constexpr size_t NameSize = 8; constexpr size_t SymbolTableEntrySize = 18; constexpr size_t RelocationSerializationSize32 = 10; +constexpr uint16_t RelocOverflow = 65535; enum ReservedSectionNum : int16_t { N_DEBUG = -2, N_ABS = -1, N_UNDEF = 0 }; diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp index 8d6849b4e1e353..8fdc0201327af6 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -156,7 +156,8 @@ DIE *DwarfCompileUnit::getOrCreateGlobalVariableDIE( DeclContext = GV->getScope(); // Add name and type. addString(*VariableDIE, dwarf::DW_AT_name, GV->getDisplayName()); - addType(*VariableDIE, GTy); + if (GTy) + addType(*VariableDIE, GTy); // Add scoping info. if (!GV->isLocalToUnit()) diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index 7b13b7f9c1c51e..88c4116b15efd8 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -1278,7 +1278,9 @@ void Verifier::visitDIGlobalVariable(const DIGlobalVariable &N) { AssertDI(N.getTag() == dwarf::DW_TAG_variable, "invalid tag", &N); AssertDI(isType(N.getRawType()), "invalid type ref", &N, N.getRawType()); - AssertDI(N.getType(), "missing global variable type", &N); + // Assert only if the global variable is not an extern + if (N.isDefinition()) + AssertDI(N.getType(), "missing global variable type", &N); if (auto *Member = N.getRawStaticDataMemberDeclaration()) { AssertDI(isa(Member), "invalid static data member declaration", &N, Member); diff --git a/llvm/lib/MC/XCOFFObjectWriter.cpp b/llvm/lib/MC/XCOFFObjectWriter.cpp index 11ce5dde47eed4..70146315e12092 100644 --- a/llvm/lib/MC/XCOFFObjectWriter.cpp +++ b/llvm/lib/MC/XCOFFObjectWriter.cpp @@ -740,8 +740,16 @@ void XCOFFObjectWriter::finalizeSectionInfo() { if (Group->empty()) continue; - for (auto &Csect : *Group) - Section->RelocationCount += Csect.Relocations.size(); + for (auto &Csect : *Group) { + const size_t CsectRelocCount = Csect.Relocations.size(); + if (CsectRelocCount >= XCOFF::RelocOverflow || + Section->RelocationCount >= XCOFF::RelocOverflow - CsectRelocCount) + report_fatal_error( + "relocation entries overflowed; overflow section is " + "not implemented yet"); + + Section->RelocationCount += CsectRelocCount; + } } } diff --git a/llvm/lib/Object/XCOFFObjectFile.cpp b/llvm/lib/Object/XCOFFObjectFile.cpp index 55d33238e772fc..533361666cf216 100644 --- a/llvm/lib/Object/XCOFFObjectFile.cpp +++ b/llvm/lib/Object/XCOFFObjectFile.cpp @@ -20,7 +20,6 @@ namespace object { static const uint8_t FunctionSym = 0x20; static const uint8_t SymTypeMask = 0x07; -static const uint16_t RelocOverflow = 65535; static const uint16_t NoRelMask = 0x0001; // Checks that [Ptr, Ptr + Size) bytes fall inside the memory buffer @@ -632,7 +631,7 @@ Expected XCOFFObjectFile::getLogicalNumberOfRelocationEntries( uint16_t SectionIndex = &Sec - sectionHeaderTable32() + 1; - if (Sec.NumberOfRelocations < RelocOverflow) + if (Sec.NumberOfRelocations < XCOFF::RelocOverflow) return Sec.NumberOfRelocations; for (const auto &Sec : sections32()) { if (Sec.Flags == XCOFF::STYP_OVRFLO && diff --git a/llvm/lib/Support/FoldingSet.cpp b/llvm/lib/Support/FoldingSet.cpp index e195089b667caf..e3d7168305af5e 100644 --- a/llvm/lib/Support/FoldingSet.cpp +++ b/llvm/lib/Support/FoldingSet.cpp @@ -86,6 +86,10 @@ void FoldingSetNodeID::AddInteger(unsigned long long I) { void FoldingSetNodeID::AddString(StringRef String) { unsigned Size = String.size(); + + unsigned NumInserts = 1 + divideCeil(Size, 4); + Bits.reserve(Bits.size() + NumInserts); + Bits.push_back(Size); if (!Size) return; diff --git a/llvm/lib/Transforms/Scalar/SROA.cpp b/llvm/lib/Transforms/Scalar/SROA.cpp index 9b3c77eae120b8..ee3bb6705c2516 100644 --- a/llvm/lib/Transforms/Scalar/SROA.cpp +++ b/llvm/lib/Transforms/Scalar/SROA.cpp @@ -94,11 +94,6 @@ #include #include -#ifndef NDEBUG -// We only use this for a debug check. -#include -#endif - using namespace llvm; using namespace llvm::sroa; @@ -115,11 +110,6 @@ STATISTIC(NumLoadsSpeculated, "Number of loads speculated to allow promotion"); STATISTIC(NumDeleted, "Number of instructions deleted"); STATISTIC(NumVectorized, "Number of vectorized aggregates"); -/// Hidden option to enable randomly shuffling the slices to help uncover -/// instability in their order. -static cl::opt SROARandomShuffleSlices("sroa-random-shuffle-slices", - cl::init(false), cl::Hidden); - /// Hidden option to experiment with completely strict handling of inbounds /// GEPs. static cl::opt SROAStrictInbounds("sroa-strict-inbounds", cl::init(false), @@ -1071,17 +1061,9 @@ AllocaSlices::AllocaSlices(const DataLayout &DL, AllocaInst &AI) llvm::remove_if(Slices, [](const Slice &S) { return S.isDead(); }), Slices.end()); -#ifndef NDEBUG - if (SROARandomShuffleSlices) { - std::mt19937 MT(static_cast( - std::chrono::system_clock::now().time_since_epoch().count())); - std::shuffle(Slices.begin(), Slices.end(), MT); - } -#endif - // Sort the uses. This arranges for the offsets to be in ascending order, // and the sizes to be in descending order. - llvm::sort(Slices); + std::stable_sort(Slices.begin(), Slices.end()); } #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) diff --git a/llvm/test/CodeGen/PowerPC/aix-xcoff-huge-relocs.ll b/llvm/test/CodeGen/PowerPC/aix-xcoff-huge-relocs.ll new file mode 100644 index 00000000000000..01e43f8b95ad35 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/aix-xcoff-huge-relocs.ll @@ -0,0 +1,46 @@ +;; This test generates 65535 relocation entries in a single section, +;; which would trigger an overflow section to be generated in 32-bit mode. +;; Since overflow section is not supported yet, we will emit an error instead of +;; generating an invalid binary for now. +; RUN: grep -v RUN: %s | \ +; RUN: sed >%t.overflow.ll 's/SIZE/65535/;s/MACRO/#/;s/#/################/g;s/#/################/g;s/#/################/g;s/#/################/g;s/#/#_/g;s/_#_\([^#]\)/\1/;s/_/, /g;s/#/i8* @c/g;' +; RUN: not --crash llc -verify-machineinstrs -mtriple powerpc-ibm-aix-xcoff \ +; RUN: -mcpu=pwr4 -mattr=-altivec -filetype=obj -o %t.o %t.overflow.ll 2>&1 | \ +; RUN: FileCheck --check-prefix=OVERFLOW %s +; OVERFLOW: LLVM ERROR: relocation entries overflowed; overflow section is not implemented yet + +;; This test generates 65534 relocation entries, an overflow section should +;; not be generated. +; RUN: grep -v RUN: %s | \ +; RUN: sed >%t.ll 's/SIZE/65534/;s/MACRO/#/;s/#/################/g;s/#/################/g;s/#/################/g;s/#/################/g;s/#/#_/g;s/_#_#_\([^#]\)/\1/;s/_/, /g;s/#/i8* @c/g;' +; RUN: llc -verify-machineinstrs -mtriple powerpc-ibm-aix-xcoff \ +; RUN: -mcpu=pwr4 -mattr=-altivec -filetype=obj -o %t.o %t.ll +; RUN: llvm-readobj --section-headers %t.o | FileCheck --check-prefix=XCOFF32 %s + +; RUN: not --crash llc -verify-machineinstrs -mtriple powerpc64-ibm-aix-xcoff \ +; RUN: -mcpu=pwr4 -mattr=-altivec -filetype=obj -o %t.o %t.overflow.ll 2>&1 | \ +; RUN: FileCheck --check-prefix=XCOFF64 %s +; RUN: not --crash llc -verify-machineinstrs -mtriple powerpc64-ibm-aix-xcoff \ +; RUN: -mcpu=pwr4 -mattr=-altivec -filetype=obj -o %t.o %t.ll 2>&1 | \ +; RUN: FileCheck --check-prefix=XCOFF64 %s +; XCOFF64: LLVM ERROR: 64-bit XCOFF object files are not supported yet. + +@c = external global i8, align 1 +@arr = global [SIZE x i8*] [MACRO], align 8 + +; XCOFF32-NOT: Name: .ovrflo +; XCOFF32-NOT: Type: STYP_OVRFLO +; XCOFF32: Section { +; XCOFF32: Name: .data +; XCOFF32-NEXT: PhysicalAddress: 0x0 +; XCOFF32-NEXT: VirtualAddress: 0x0 +; XCOFF32-NEXT: Size: 0x3FFF8 +; XCOFF32-NEXT: RawDataOffset: 0x64 +; XCOFF32-NEXT: RelocationPointer: 0x4005C +; XCOFF32-NEXT: LineNumberPointer: 0x0 +; XCOFF32-NEXT: NumberOfRelocations: 65534 +; XCOFF32-NEXT: NumberOfLineNumbers: 0 +; XCOFF32-NEXT: Type: STYP_DATA (0x40) +; XCOFF32-NEXT: } +; XCOFF32-NOT: Name: .ovrflo +; XCOFF32-NOT: Type: STYP_OVRFLO diff --git a/llvm/test/DebugInfo/BPF/extern-void.ll b/llvm/test/DebugInfo/BPF/extern-void.ll new file mode 100644 index 00000000000000..3bf8e27623e76d --- /dev/null +++ b/llvm/test/DebugInfo/BPF/extern-void.ll @@ -0,0 +1,81 @@ +; RUN: llc -march=bpfel -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s +; RUN: llc -march=bpfeb -filetype=asm -o - %s | FileCheck -check-prefixes=CHECK %s +; +; Source code: +; extern void bla1; +; void *test1() { +; void *x = &bla1; +; return x; +; } +; +; extern const void bla2; +; const void *test2() { +; const void *x = &bla2; +; return x; +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm t.c + +@bla1 = external dso_local global i8, align 1, !dbg !0 +@bla2 = external dso_local constant i8, align 1, !dbg !6 + +; Function Attrs: norecurse nounwind readnone +define dso_local nonnull i8* @test1() local_unnamed_addr #0 !dbg !13 { +entry: + call void @llvm.dbg.value(metadata i8* @bla1, metadata !18, metadata !DIExpression()), !dbg !19 + ret i8* @bla1, !dbg !20 +} + +; Function Attrs: norecurse nounwind readnone +define dso_local nonnull i8* @test2() local_unnamed_addr #0 !dbg !21 { +entry: + call void @llvm.dbg.value(metadata i8* @bla2, metadata !26, metadata !DIExpression()), !dbg !27 + ret i8* @bla2, !dbg !28 +} + +; CHECK: .quad bla1 +; CHECK-NEXT: DW_TAG_variable +; +; CHECK: .quad bla2 +; CHECK-NEXT: DW_TAG_const_type +; CHECK-NEXT: DW_TAG_subprogram + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #1 + +attributes #0 = { norecurse nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone speculatable willreturn } + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!9, !10, !11} +!llvm.ident = !{!12} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "bla1", scope: !2, file: !3, line: 1, isLocal: false, isDefinition: false) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 11.0.0 (https://github.com/llvm/llvm-project.git 8a8c6913a931e8bbd119012f4badd81155a0f48a)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, splitDebugInlining: false, nameTableKind: None) +!3 = !DIFile(filename: "t.c", directory: "/home/yhs/tmp3") +!4 = !{} +!5 = !{!0, !6} +!6 = !DIGlobalVariableExpression(var: !7, expr: !DIExpression()) +!7 = distinct !DIGlobalVariable(name: "bla2", scope: !2, file: !3, line: 7, type: !8, isLocal: false, isDefinition: false) +!8 = !DIDerivedType(tag: DW_TAG_const_type, baseType: null) +!9 = !{i32 7, !"Dwarf Version", i32 4} +!10 = !{i32 2, !"Debug Info Version", i32 3} +!11 = !{i32 1, !"wchar_size", i32 4} +!12 = !{!"clang version 11.0.0 (https://github.com/llvm/llvm-project.git 8a8c6913a931e8bbd119012f4badd81155a0f48a)"} +!13 = distinct !DISubprogram(name: "test1", scope: !3, file: !3, line: 2, type: !14, scopeLine: 2, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !17) +!14 = !DISubroutineType(types: !15) +!15 = !{!16} +!16 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64) +!17 = !{!18} +!18 = !DILocalVariable(name: "x", scope: !13, file: !3, line: 3, type: !16) +!19 = !DILocation(line: 0, scope: !13) +!20 = !DILocation(line: 4, column: 3, scope: !13) +!21 = distinct !DISubprogram(name: "test2", scope: !3, file: !3, line: 8, type: !22, scopeLine: 8, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !25) +!22 = !DISubroutineType(types: !23) +!23 = !{!24} +!24 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !8, size: 64) +!25 = !{!26} +!26 = !DILocalVariable(name: "x", scope: !21, file: !3, line: 9, type: !24) +!27 = !DILocation(line: 0, scope: !21) +!28 = !DILocation(line: 10, column: 3, scope: !21) diff --git a/llvm/test/DebugInfo/BPF/lit.local.cfg b/llvm/test/DebugInfo/BPF/lit.local.cfg new file mode 100644 index 00000000000000..a4ab2624af6142 --- /dev/null +++ b/llvm/test/DebugInfo/BPF/lit.local.cfg @@ -0,0 +1,2 @@ +if not 'BPF' in config.root.targets: + config.unsupported = True diff --git a/llvm/test/Transforms/SROA/phi-gep.ll b/llvm/test/Transforms/SROA/phi-gep.ll index 2763c71d401bb5..a7bc6319fc9148 100644 --- a/llvm/test/Transforms/SROA/phi-gep.ll +++ b/llvm/test/Transforms/SROA/phi-gep.ll @@ -367,6 +367,55 @@ exit: unreachable } +define i32 @test_sroa_gep_cast_phi_gep(i1 %cond) { +; CHECK-LABEL: @test_sroa_gep_cast_phi_gep( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[A_SROA_0:%.*]] = alloca i32, align 4 +; CHECK-NEXT: [[A_SROA_0_0_GEP_A_CAST_TO_I32_SROA_CAST:%.*]] = bitcast i32* [[A_SROA_0]] to float* +; CHECK-NEXT: [[A_SROA_0_0_GEP_A_CAST_TO_I32_SROA_CAST2:%.*]] = bitcast i32* [[A_SROA_0]] to float* +; CHECK-NEXT: [[A_SROA_0_0_GEP_SROA_CAST:%.*]] = bitcast i32* [[A_SROA_0]] to float* +; CHECK-NEXT: store i32 1065353216, i32* [[A_SROA_0]], align 4 +; CHECK-NEXT: br i1 [[COND:%.*]], label [[FOR:%.*]], label [[END:%.*]] +; CHECK: for: +; CHECK-NEXT: [[PHI_I:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[I:%.*]], [[FOR]] ] +; CHECK-NEXT: [[PHI:%.*]] = phi float* [ [[A_SROA_0_0_GEP_A_CAST_TO_I32_SROA_CAST]], [[ENTRY]] ], [ [[GEP_FOR_CAST_TO_I32:%.*]], [[FOR]] ] +; CHECK-NEXT: [[PHI_SROA_PHI:%.*]] = phi float* [ [[A_SROA_0_0_GEP_SROA_CAST]], [[ENTRY]] ], [ [[GEP_FOR_CAST_TO_I32_SROA_GEP:%.*]], [[FOR]] ] +; CHECK-NEXT: [[I]] = add i32 [[PHI_I]], 1 +; CHECK-NEXT: [[GEP_FOR_CAST:%.*]] = bitcast float* [[PHI_SROA_PHI]] to i32* +; CHECK-NEXT: [[GEP_FOR_CAST_TO_I32]] = bitcast i32* [[GEP_FOR_CAST]] to float* +; CHECK-NEXT: [[GEP_FOR_CAST_TO_I32_SROA_GEP]] = getelementptr inbounds float, float* [[GEP_FOR_CAST_TO_I32]], i32 0 +; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ult i32 [[I]], 10 +; CHECK-NEXT: br i1 [[LOOP_COND]], label [[FOR]], label [[END]] +; CHECK: end: +; CHECK-NEXT: [[PHI_END:%.*]] = phi float* [ [[A_SROA_0_0_GEP_A_CAST_TO_I32_SROA_CAST2]], [[ENTRY]] ], [ [[PHI]], [[FOR]] ] +; CHECK-NEXT: [[PHI_END_1:%.*]] = bitcast float* [[PHI_END]] to i32* +; CHECK-NEXT: [[LOAD:%.*]] = load i32, i32* [[PHI_END_1]], align 4 +; CHECK-NEXT: ret i32 [[LOAD]] +; +entry: + %a = alloca %pair, align 4 + %gep_a = getelementptr inbounds %pair, %pair* %a, i32 0, i32 1 + %gep_a_cast_to_float = bitcast i32* %gep_a to float* + store float 1.0, float* %gep_a_cast_to_float, align 4 + br i1 %cond, label %for, label %end + +for: + %phi_i = phi i32 [ 0, %entry ], [ %i, %for ] + %phi = phi float* [ %gep_a_cast_to_float, %entry], [ %gep_for_cast_to_float, %for ] + %i = add i32 %phi_i, 1 + %gep_for = getelementptr inbounds float, float* %phi, i32 0 + %gep_for_cast = bitcast float* %gep_for to i32* + %gep_for_cast_to_float = bitcast i32* %gep_for_cast to float* + %loop.cond = icmp ult i32 %i, 10 + br i1 %loop.cond, label %for, label %end + +end: + %phi_end = phi float* [ %gep_a_cast_to_float, %entry], [ %phi, %for ] + %phi_end.1 = bitcast float* %phi_end to i32* + %load = load i32, i32* %phi_end.1, align 4 + ret i32 %load +} + declare %pair* @foo() declare i32 @__gxx_personality_v0(...)