Skip to content

Commit

Permalink
Merged master:552c6c232872 into amd-gfx:28482ff9f121
Browse files Browse the repository at this point in the history
Local branch amd-gfx 28482ff Merged master:32f77eea2d0f into amd-gfx:a9377682fb5c
Remote branch master 552c6c2 PR44406: Follow behavior of array bound constant folding in more recent versions of GCC.
  • Loading branch information
Sw authored and Sw committed Oct 16, 2020
2 parents 28482ff + 552c6c2 commit 5efa00a
Show file tree
Hide file tree
Showing 105 changed files with 1,269 additions and 494 deletions.
67 changes: 36 additions & 31 deletions clang/docs/UsersManual.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2479,8 +2479,8 @@ Differences between various standard modes
------------------------------------------

clang supports the -std option, which changes what language mode clang uses.
The supported modes for C are c89, gnu89, c99, gnu99, c11, gnu11, c17, gnu17,
c2x, gnu2x, and various aliases for those modes. If no -std option is
The supported modes for C are c89, gnu89, c94, c99, gnu99, c11, gnu11, c17,
gnu17, c2x, gnu2x, and various aliases for those modes. If no -std option is
specified, clang defaults to gnu17 mode. Many C99 and C11 features are
supported in earlier modes as a conforming extension, with a warning. Use
``-pedantic-errors`` to request an error if a feature from a later standard
Expand All @@ -2489,34 +2489,36 @@ revision is used in an earlier mode.
Differences between all ``c*`` and ``gnu*`` modes:

- ``c*`` modes define "``__STRICT_ANSI__``".
- Target-specific defines not prefixed by underscores, like "linux",
- Target-specific defines not prefixed by underscores, like ``linux``,
are defined in ``gnu*`` modes.
- Trigraphs default to being off in ``gnu*`` modes; they can be enabled by
the -trigraphs option.
- The parser recognizes "asm" and "typeof" as keywords in ``gnu*`` modes;
the variants "``__asm__``" and "``__typeof__``" are recognized in all
- Trigraphs default to being off in ``gnu*`` modes; they can be enabled
by the ``-trigraphs`` option.
- The parser recognizes ``asm`` and ``typeof`` as keywords in ``gnu*`` modes;
the variants ``__asm__`` and ``__typeof__`` are recognized in all modes.
- The parser recognizes ``inline`` as a keyword in ``gnu*`` mode, in
addition to recognizing it in the ``*99`` and later modes for which it is
part of the ISO C standard. The variant ``__inline__`` is recognized in all
modes.
- The Apple "blocks" extension is recognized by default in ``gnu*`` modes
on some platforms; it can be enabled in any mode with the "-fblocks"
on some platforms; it can be enabled in any mode with the ``-fblocks``
option.
- Arrays that are VLA's according to the standard, but which can be
constant folded by the frontend are treated as fixed size arrays.
This occurs for things like "int X[(1, 2)];", which is technically a
VLA. ``c*`` modes are strictly compliant and treat these as VLAs.

Differences between ``*89`` and ``*99`` modes:
Differences between ``*89`` and ``*94`` modes:

- The ``*99`` modes default to implementing "inline" as specified in C99,
while the ``*89`` modes implement the GNU version. This can be
overridden for individual functions with the ``__gnu_inline__``
attribute.
- Digraphs are not recognized in c89 mode.
- The scope of names defined inside a "for", "if", "switch", "while",
or "do" statement is different. (example: "``if ((struct x {int
x;}*)0) {}``".)

Differences between ``*94`` and ``*99`` modes:

- The ``*99`` modes default to implementing ``inline`` / ``__inline__``
as specified in C99, while the ``*89`` modes implement the GNU version.
This can be overridden for individual functions with the ``__gnu_inline__``
attribute.
- The scope of names defined inside a ``for``, ``if``, ``switch``, ``while``,
or ``do`` statement is different. (example: ``if ((struct x {int x;}*)0)
{}``.)
- ``__STDC_VERSION__`` is not defined in ``*89`` modes.
- "inline" is not recognized as a keyword in c89 mode.
- "restrict" is not recognized as a keyword in ``*89`` modes.
- ``inline`` is not recognized as a keyword in ``c89`` mode.
- ``restrict`` is not recognized as a keyword in ``*89`` modes.
- Commas are allowed in integer constant expressions in ``*99`` modes.
- Arrays which are not lvalues are not implicitly promoted to pointers
in ``*89`` modes.
Expand All @@ -2538,9 +2540,7 @@ clang tries to be compatible with gcc as much as possible, but some gcc
extensions are not implemented yet:

- clang does not support decimal floating point types (``_Decimal32`` and
friends) or fixed-point types (``_Fract`` and friends); nobody has
expressed interest in these features yet, so it's hard to say when
they will be implemented.
friends) yet.
- clang does not support nested functions; this is a complex feature
which is infrequently used, so it is unlikely to be implemented
anytime soon. In C++11 it can be emulated by assigning lambda
Expand Down Expand Up @@ -2590,10 +2590,12 @@ Intentionally unsupported GCC extensions
the extension appears to be rarely used. Note that clang *does*
support flexible array members (arrays with a zero or unspecified
size at the end of a structure).
- clang does not have an equivalent to gcc's "fold"; this means that
clang doesn't accept some constructs gcc might accept in contexts
where a constant expression is required, like "x-x" where x is a
variable.
- GCC accepts many expression forms that are not valid integer constant
expressions in bit-field widths, enumerator constants, case labels,
and in array bounds at global scope. Clang also accepts additional
expression forms in these contexts, but constructs that GCC accepts due to
simplifications GCC performs while parsing, such as ``x - x`` (where ``x`` is a
variable) will likely never be accepted by Clang.
- clang does not support ``__builtin_apply`` and friends; this extension
is extremely obscure and difficult to implement reliably.

Expand Down Expand Up @@ -2634,8 +2636,11 @@ C++ Language Features
=====================

clang fully implements all of standard C++98 except for exported
templates (which were removed in C++11), and all of standard C++11
and the current draft standard for C++1y.
templates (which were removed in C++11), all of standard C++11,
C++14, and C++17, and most of C++20.

See the `C++ support in Clang <https://clang.llvm.org/cxx_status.html>` page
for detailed information on C++ feature support across Clang versions.

Controlling implementation limits
---------------------------------
Expand Down
7 changes: 3 additions & 4 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,9 @@ def err_vla_decl_has_static_storage : Error<
"variable length array declaration cannot have 'static' storage duration">;
def err_vla_decl_has_extern_linkage : Error<
"variable length array declaration cannot have 'extern' linkage">;
def ext_vla_folded_to_constant : Extension<
"variable length array folded to constant array as an extension">, InGroup<GNUFoldingConstant>;
def ext_vla_folded_to_constant : ExtWarn<
"variable length array folded to constant array as an extension">,
InGroup<GNUFoldingConstant>;
def err_vla_unsupported : Error<
"variable length arrays are not supported for the current target">;
def note_vla_unsupported : Note<
Expand Down Expand Up @@ -5474,8 +5475,6 @@ def warn_flag_enum_constant_out_of_range : Warning<
"enumeration value %0 is out of range of flags in enumeration type %1">,
InGroup<FlagEnum>;

def warn_illegal_constant_array_size : Extension<
"size of static array must be an integer constant expression">;
def err_vm_decl_in_file_scope : Error<
"variably modified type declaration not allowed at file scope">;
def err_vm_decl_has_extern_linkage : Error<
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/AST/ExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2528,6 +2528,11 @@ static llvm::RoundingMode getActiveRoundingMode(EvalInfo &Info, const Expr *E,
/// Check if the given evaluation result is allowed for constant evaluation.
static bool checkFloatingPointResult(EvalInfo &Info, const Expr *E,
APFloat::opStatus St) {
// In a constant context, assume that any dynamic rounding mode or FP
// exception state matches the default floating-point environment.
if (Info.InConstantContext)
return true;

FPOptions FPO = E->getFPFeaturesInEffect(Info.Ctx.getLangOpts());
if ((St & APFloat::opInexact) &&
FPO.getRoundingMode() == llvm::RoundingMode::Dynamic) {
Expand Down
6 changes: 4 additions & 2 deletions clang/lib/CodeGen/CGExprAgg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1759,7 +1759,9 @@ void AggExprEmitter::VisitDesignatedInitUpdateExpr(DesignatedInitUpdateExpr *E)
/// non-zero bytes that will be stored when outputting the initializer for the
/// specified initializer expression.
static CharUnits GetNumNonZeroBytesInInit(const Expr *E, CodeGenFunction &CGF) {
E = E->IgnoreParens();
if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E))
E = MTE->getSubExpr();
E = E->IgnoreParenNoopCasts(CGF.getContext());

// 0 and 0.0 won't require any non-zero stores!
if (isSimpleZero(E, CGF)) return CharUnits::Zero();
Expand Down Expand Up @@ -1808,7 +1810,7 @@ static CharUnits GetNumNonZeroBytesInInit(const Expr *E, CodeGenFunction &CGF) {
}
}


// FIXME: This overestimates the number of non-zero bytes for bit-fields.
CharUnits NumNonZeroBytes = CharUnits::Zero();
for (unsigned i = 0, e = ILE->getNumInits(); i != e; ++i)
NumNonZeroBytes += GetNumNonZeroBytesInInit(ILE->getInit(i), CGF);
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Driver/ToolChains/AMDGPU.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class LLVM_LIBRARY_VISIBILITY AMDGPUToolChain : public Generic_ELF {
public:
AMDGPUToolChain(const Driver &D, const llvm::Triple &Triple,
const llvm::opt::ArgList &Args);
unsigned GetDefaultDwarfVersion() const override { return 4; }
unsigned GetDefaultDwarfVersion() const override { return 5; }
bool IsIntegratedAssemblerDefault() const override { return true; }
bool IsMathErrnoDefault() const override { return false; }

Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Driver/ToolChains/HIP.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ class LLVM_LIBRARY_VISIBILITY HIPToolChain final : public ROCMToolChain {
computeMSVCVersion(const Driver *D,
const llvm::opt::ArgList &Args) const override;

unsigned GetDefaultDwarfVersion() const override { return 4; }
unsigned GetDefaultDwarfVersion() const override { return 5; }

const ToolChain &HostTC;

Expand Down
53 changes: 31 additions & 22 deletions clang/lib/Format/UnwrappedLineParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2612,32 +2612,15 @@ void UnwrappedLineParser::parseObjCInterfaceOrImplementation() {
// @interface can be followed by a lightweight generic
// specialization list, then either a base class or a category.
if (FormatTok->Tok.is(tok::less)) {
// Unlike protocol lists, generic parameterizations support
// nested angles:
//
// @interface Foo<ValueType : id <NSCopying, NSSecureCoding>> :
// NSObject <NSCopying, NSSecureCoding>
//
// so we need to count how many open angles we have left.
unsigned NumOpenAngles = 1;
do {
nextToken();
// Early exit in case someone forgot a close angle.
if (FormatTok->isOneOf(tok::semi, tok::l_brace) ||
FormatTok->Tok.isObjCAtKeyword(tok::objc_end))
break;
if (FormatTok->Tok.is(tok::less))
++NumOpenAngles;
else if (FormatTok->Tok.is(tok::greater)) {
assert(NumOpenAngles > 0 && "'>' makes NumOpenAngles negative");
--NumOpenAngles;
}
} while (!eof() && NumOpenAngles != 0);
nextToken(); // Skip '>'.
parseObjCLightweightGenerics();
}
if (FormatTok->Tok.is(tok::colon)) {
nextToken();
nextToken(); // base class name
// The base class can also have lightweight generics applied to it.
if (FormatTok->Tok.is(tok::less)) {
parseObjCLightweightGenerics();
}
} else if (FormatTok->Tok.is(tok::l_paren))
// Skip category, if present.
parseParens();
Expand All @@ -2658,6 +2641,32 @@ void UnwrappedLineParser::parseObjCInterfaceOrImplementation() {
parseObjCUntilAtEnd();
}

void UnwrappedLineParser::parseObjCLightweightGenerics() {
assert(FormatTok->Tok.is(tok::less));
// Unlike protocol lists, generic parameterizations support
// nested angles:
//
// @interface Foo<ValueType : id <NSCopying, NSSecureCoding>> :
// NSObject <NSCopying, NSSecureCoding>
//
// so we need to count how many open angles we have left.
unsigned NumOpenAngles = 1;
do {
nextToken();
// Early exit in case someone forgot a close angle.
if (FormatTok->isOneOf(tok::semi, tok::l_brace) ||
FormatTok->Tok.isObjCAtKeyword(tok::objc_end))
break;
if (FormatTok->Tok.is(tok::less))
++NumOpenAngles;
else if (FormatTok->Tok.is(tok::greater)) {
assert(NumOpenAngles > 0 && "'>' makes NumOpenAngles negative");
--NumOpenAngles;
}
} while (!eof() && NumOpenAngles != 0);
nextToken(); // Skip '>'.
}

// Returns true for the declaration/definition form of @protocol,
// false for the expression form.
bool UnwrappedLineParser::parseObjCProtocol() {
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Format/UnwrappedLineParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ class UnwrappedLineParser {
// parses the record as a child block, i.e. if the class declaration is an
// expression.
void parseRecord(bool ParseAsExpr = false);
void parseObjCLightweightGenerics();
void parseObjCMethod();
void parseObjCProtocolList();
void parseObjCUntilAtEnd();
Expand Down
37 changes: 25 additions & 12 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5932,9 +5932,14 @@ static QualType TryToFixInvalidVariablyModifiedType(QualType T,
const VariableArrayType* VLATy = dyn_cast<VariableArrayType>(T);
if (!VLATy)
return QualType();
// FIXME: We should probably handle this case
if (VLATy->getElementType()->isVariablyModifiedType())
return QualType();

QualType ElemTy = VLATy->getElementType();
if (ElemTy->isVariablyModifiedType()) {
ElemTy = TryToFixInvalidVariablyModifiedType(ElemTy, Context,
SizeIsNegative, Oversized);
if (ElemTy.isNull())
return QualType();
}

Expr::EvalResult Result;
if (!VLATy->getSizeExpr() ||
Expand All @@ -5950,16 +5955,18 @@ static QualType TryToFixInvalidVariablyModifiedType(QualType T,
}

// Check whether the array is too large to be addressed.
unsigned ActiveSizeBits
= ConstantArrayType::getNumAddressingBits(Context, VLATy->getElementType(),
Res);
unsigned ActiveSizeBits =
(!ElemTy->isDependentType() && !ElemTy->isVariablyModifiedType() &&
!ElemTy->isIncompleteType() && !ElemTy->isUndeducedType())
? ConstantArrayType::getNumAddressingBits(Context, ElemTy, Res)
: Res.getActiveBits();
if (ActiveSizeBits > ConstantArrayType::getMaxSizeBits(Context)) {
Oversized = Res;
return QualType();
}

return Context.getConstantArrayType(
VLATy->getElementType(), Res, VLATy->getSizeExpr(), ArrayType::Normal, 0);
return Context.getConstantArrayType(ElemTy, Res, VLATy->getSizeExpr(),
ArrayType::Normal, 0);
}

static void
Expand All @@ -5985,7 +5992,13 @@ FixInvalidVariablyModifiedTypeLoc(TypeLoc SrcTL, TypeLoc DstTL) {
ArrayTypeLoc DstATL = DstTL.castAs<ArrayTypeLoc>();
TypeLoc SrcElemTL = SrcATL.getElementLoc();
TypeLoc DstElemTL = DstATL.getElementLoc();
DstElemTL.initializeFullCopy(SrcElemTL);
if (VariableArrayTypeLoc SrcElemATL =
SrcElemTL.getAs<VariableArrayTypeLoc>()) {
ConstantArrayTypeLoc DstElemATL = DstElemTL.castAs<ConstantArrayTypeLoc>();
FixInvalidVariablyModifiedTypeLoc(SrcElemATL, DstElemATL);
} else {
DstElemTL.initializeFullCopy(SrcElemTL);
}
DstATL.setLBracketLoc(SrcATL.getLBracketLoc());
DstATL.setSizeExpr(SrcATL.getSizeExpr());
DstATL.setRBracketLoc(SrcATL.getRBracketLoc());
Expand Down Expand Up @@ -6115,7 +6128,7 @@ Sema::CheckTypedefForVariablyModifiedType(Scope *S, TypedefNameDecl *NewTD) {
SizeIsNegative,
Oversized);
if (FixedTInfo) {
Diag(NewTD->getLocation(), diag::warn_illegal_constant_array_size);
Diag(NewTD->getLocation(), diag::ext_vla_folded_to_constant);
NewTD->setTypeSourceInfo(FixedTInfo);
} else {
if (SizeIsNegative)
Expand Down Expand Up @@ -7984,7 +7997,7 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) {
return;
}

Diag(NewVD->getLocation(), diag::warn_illegal_constant_array_size);
Diag(NewVD->getLocation(), diag::ext_vla_folded_to_constant);
NewVD->setType(FixedT);
NewVD->setTypeSourceInfo(FixedTInfo);
}
Expand Down Expand Up @@ -16675,7 +16688,7 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
SizeIsNegative,
Oversized);
if (FixedTInfo) {
Diag(Loc, diag::warn_illegal_constant_array_size);
Diag(Loc, diag::ext_vla_folded_to_constant);
TInfo = FixedTInfo;
T = FixedTInfo->getType();
} else {
Expand Down
6 changes: 1 addition & 5 deletions clang/lib/Sema/SemaType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2273,13 +2273,9 @@ static ExprResult checkArraySize(Sema &S, Expr *&ArraySize,
}
} Diagnoser(VLADiag, VLAIsError);

// FIXME: GCC does *not* allow folding here in general; see PR44406.
// For GCC compatibility, we should remove this folding and leave it to
// TryFixVariablyModifiedType to convert VLAs to constant array types.
ExprResult R = S.VerifyIntegerConstantExpression(
ArraySize, &SizeVal, Diagnoser,
(S.LangOpts.GNUMode || S.LangOpts.OpenCL) ? Sema::AllowFold
: Sema::NoFold);
S.LangOpts.OpenCL ? Sema::AllowFold : Sema::NoFold);
if (Diagnoser.IsVLA)
return ExprResult();
return R;
Expand Down
1 change: 1 addition & 0 deletions clang/test/CXX/basic/basic.types/p10.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ constexpr int f(ArrBad) { return 0; } // expected-error {{1st parameter type 'Ar
constexpr int arb(int n) {
int a[n]; // expected-error {{variable of non-literal type 'int [n]' cannot be defined in a constexpr function}}
}
// expected-warning@+1 {{variable length array folded to constant array as an extension}}
constexpr long Overflow[ // expected-error {{constexpr variable cannot have non-literal type 'long const[(1 << 30) << 2]'}}
(1 << 30) << 2]{}; // expected-warning {{requires 34 bits to represent}}

Expand Down
4 changes: 2 additions & 2 deletions clang/test/CXX/drs/dr3xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -898,8 +898,8 @@ namespace dr367 { // dr367: yes
int c[true ? *new int : 4]; // expected-error 2{{variable length array}} expected-note {{read of uninitialized}}
int d[true ? 4 : *new int];
#if __cplusplus < 201103L
// expected-error@-4 {{variable length array}} expected-error@-4 {{constant expression}}
// expected-error@-3 {{variable length array}} expected-error@-3 {{constant expression}}
// expected-error@-4 2{{variable length array}}
// expected-error@-3 2{{variable length array}}
#endif
}

Expand Down
12 changes: 12 additions & 0 deletions clang/test/CodeGen/vla.c
Original file line number Diff line number Diff line change
Expand Up @@ -210,3 +210,15 @@ void test9(int n, int a[static n]) { }
void test10(int a[static 0]) {}
// NULL-INVALID: define void @test10(i32* nonnull align 4 %a)
// NULL-VALID: define void @test10(i32* align 4 %a)

const int constant = 32;
// CHECK: define {{.*}}pr44406(
int pr44406() {
int n = 0;
// Do not fold this VLA to an array of constant bound; that would miscompile
// this testcase.
char c[1][(constant - constant) + 3];
// CHECK: store i32 1,
sizeof(c[n = 1]);
return n;
}
Loading

0 comments on commit 5efa00a

Please sign in to comment.