Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -2176,6 +2176,11 @@ "argument to 'section' attribute is not valid for this target: %0">; def warn_mismatched_section : Warning< "section does not match previous declaration">, InGroup
; +def err_attribute_section_bss_nonzero : Error< + "variables placed in BSS section must be zero-initialized, but " + "%0 is initialized with a non-zero value">; +def err_attribute_section_bss_function : Error< + "functions cannot be placed in BSS section">; def err_anonymous_property: Error< "anonymous property is not supported">; Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -5302,6 +5302,99 @@ return false; } +static bool isValueNonZero(const APValue &Value) { + switch (Value.getKind()) { + case APValue::Uninitialized: + return false; + case APValue::Int: + return Value.getInt() != 0; + case APValue::Float: + return Value.getFloat().isNonZero(); + case APValue::ComplexInt: { + bool isRealNonZero = Value.getComplexIntReal() != 0; + bool isImagNonZero = Value.getComplexIntImag() != 0; + return isRealNonZero || isImagNonZero; + } + case APValue::ComplexFloat: { + bool isRealNonZero = Value.getComplexFloatReal().isNonZero(); + bool isImagNonZero = Value.getComplexFloatImag().isNonZero(); + return isRealNonZero || isImagNonZero; + } + case APValue::Vector: { + for (unsigned i = 0, e = Value.getVectorLength(); i < e; ++i) { + if (isValueNonZero(Value.getVectorElt(i))) + return true; + } + return false; + } + case APValue::Array: { + for (unsigned i = 0, e = Value.getArrayInitializedElts(); i < e; ++i) { + if (isValueNonZero(Value.getArrayInitializedElt(i))) + return true; + } + return false; + } + case APValue::Struct: { + for (unsigned i = 0, e = Value.getStructNumBases(); i < e; ++i) { + if (isValueNonZero(Value.getStructBase(i))) + return true; + } + for (unsigned i = 0, e = Value.getStructNumFields(); i < e; ++i) { + if (isValueNonZero(Value.getStructField(i))) + return true; + } + return false; + } + case APValue::Union: + return isValueNonZero(Value.getUnionValue()); + + // For other kinds we cannot tell and assume non-zero. + case APValue::LValue: + return false; + case APValue::MemberPointer: + return false; + case APValue::AddrLabelDiff: + return false; + } + + llvm_unreachable("unhandled APValue kind"); +} + +static bool isExpressionNonZero(const Expr *E, Sema &S, const VarDecl &VD) { + APValue Result; + SmallVector Notes; + if (E->EvaluateAsInitializer(Result, S.Context, &VD, Notes)) + return isValueNonZero(Result); + + if (const auto *InitList = dyn_cast(E)) { + for (Stmt *Statement : *InitList) { + if (const auto *InitElt = dyn_cast(Statement)) { + if (isExpressionNonZero(InitElt, S, VD)) + return true; + } else + return false; + } + return false; + } + return false; // Expr E is neither evaluable initializer nor initializer list. +} + +static void checkAttributeSectionBSS(Sema &S, VarDecl &VD) { + if (const auto *SA = VD.getAttr()) { + if (SA->getName().startswith(".bss")) { + if (const Expr *InitExpr = VD.getInit()) { + if (isExpressionNonZero(InitExpr, S, VD)) { + S.Diag(SA->getLocation(), + diag::err_attribute_section_bss_nonzero) + << &VD << SA->getRange() << InitExpr->getSourceRange(); + + VD.dropAttr(); + } + } + } + } +} + static void checkAttributesAfterMerging(Sema &S, NamedDecl &ND) { // Ensure that an auto decl is deduced otherwise the checks below might cache // the wrong linkage. @@ -5330,6 +5423,7 @@ S.Diag(Attr->getLocation(), diag::err_alias_is_definition) << VD; VD->dropAttr(); } + checkAttributeSectionBSS(S, *VD); } } Index: lib/Sema/SemaDeclAttr.cpp =================================================================== --- lib/Sema/SemaDeclAttr.cpp +++ lib/Sema/SemaDeclAttr.cpp @@ -2396,6 +2396,12 @@ SectionAttr *NewAttr = S.mergeSectionAttr(D, Attr.getRange(), Str, Index); if (NewAttr) D->addAttr(NewAttr); + + if (isa(D) && Str.startswith(".bss")) { + S.Diag(Attr.getLoc(), diag::err_attribute_section_bss_function) + << NewAttr->getRange(); + D->dropAttr(); + } } // Check for things we'd like to warn about, no errors or validation for now. Index: test/Sema/attr-section-bss.c =================================================================== --- /dev/null +++ test/Sema/attr-section-bss.c @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 -verify -fsyntax-only %s + +__attribute__((section(".bss.Name"))) int a = 3 * 5; // expected-error {{variables placed in BSS section must be zero-initialized, but 'a' is initialized with a non-zero value}} +__attribute__((section(".bss.Name"))) int correct_a = 0 * 5; + +__attribute__((section(".bss.Name"))) float x = 3 * 0.997; // expected-error {{variables placed in BSS section must be zero-initialized, but 'x' is initialized with a non-zero value}} +__attribute__((section(".bss.Name"))) float correct_x = 0.0 * 0.997; + +__attribute__((section(".bss.Sth"))) void foo() {} // expected-error {{functions cannot be placed in BSS section}} + +__attribute__((section(".bss.Name"))) int arr[] = {0, 2, 0}; // expected-error {{variables placed in BSS section must be zero-initialized, but 'arr' is initialized with a non-zero value}} +__attribute__((section(".bss.Name"))) int correct_arr[] = {0, 0, 0}; + +typedef struct { + float a; + int b; + double arr[3]; +} TestStruct; + +__attribute__((section(".bss"))) TestStruct str = {0.0, 0, {0.0, 1.0, 0.0}}; // expected-error {{variables placed in BSS section must be zero-initialized, but 'str' is initialized with a non-zero value}}} +__attribute__((section(".bss"))) TestStruct correct_str = {0.0, 0, {0.0, 0.0, 0.0}}; + +typedef struct {} EmptyStruct; +__attribute__((section(".bss.Name"))) EmptyStruct estr = {}; +