summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Wennborg <hans@hanshq.net>2015-01-20 19:27:49 +0000
committerHans Wennborg <hans@hanshq.net>2015-01-20 19:27:49 +0000
commite2b4aa19430a7f0eb9a166b701e40c3dc4cdd53b (patch)
tree54b2a65851678bbf78c27a2403d70fd55553effe
parent2e151343a8de90fc29d2081c02fcb50b48fd23bd (diff)
Revert "r222906 - Create a new 'flag_enum' attribute."
git-svn-id: https://llvm.org/svn/llvm-project/cfe/branches/release_36@226593 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/Basic/Attr.td23
-rw-r--r--include/clang/Basic/AttrDocs.td10
-rw-r--r--include/clang/Basic/DiagnosticGroups.td1
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td5
-rw-r--r--include/clang/Sema/AttributeList.h1
-rw-r--r--include/clang/Sema/Sema.h6
-rw-r--r--lib/Sema/SemaDecl.cpp86
-rw-r--r--lib/Sema/SemaDeclAttr.cpp3
-rw-r--r--lib/Sema/SemaStmt.cpp147
-rw-r--r--test/Sema/attr-flag-enum.c73
-rw-r--r--test/SemaCXX/attr-flag-enum-reject.cpp4
-rw-r--r--utils/TableGen/ClangAttrEmitter.cpp7
12 files changed, 80 insertions, 286 deletions
diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td
index 8437461114..3ed7f8d6b1 100644
--- a/include/clang/Basic/Attr.td
+++ b/include/clang/Basic/Attr.td
@@ -224,14 +224,12 @@ class SubjectList<list<AttrSubject> subjects, SubjectDiag diag = WarnDiag,
string CustomDiag = customDiag;
}
-class LangOpt<string name, bit negated = 0> {
+class LangOpt<string name> {
string Name = name;
- bit Negated = negated;
}
def MicrosoftExt : LangOpt<"MicrosoftExt">;
def Borland : LangOpt<"Borland">;
def CUDA : LangOpt<"CUDA">;
-def COnly : LangOpt<"CPlusPlus", 1>;
// Defines targets for target-specific attributes. The list of strings should
// specify architectures for which the target applies, based off the ArchType
@@ -709,25 +707,6 @@ def MinSize : InheritableAttr {
let Documentation = [Undocumented];
}
-def FlagEnum : InheritableAttr {
- let Spellings = [GNU<"flag_enum">];
- let Subjects = SubjectList<[Enum]>;
- let Documentation = [FlagEnumDocs];
- let LangOpts = [COnly];
- let AdditionalMembers = [{
-private:
- llvm::APInt FlagBits;
-public:
- llvm::APInt &getFlagBits() {
- return FlagBits;
- }
-
- const llvm::APInt &getFlagBits() const {
- return FlagBits;
- }
-}];
-}
-
def Flatten : InheritableAttr {
let Spellings = [GCC<"flatten">];
let Subjects = SubjectList<[Function], ErrorDiag>;
diff --git a/include/clang/Basic/AttrDocs.td b/include/clang/Basic/AttrDocs.td
index 918abb6072..530c6e7d10 100644
--- a/include/clang/Basic/AttrDocs.td
+++ b/include/clang/Basic/AttrDocs.td
@@ -1196,16 +1196,6 @@ behavior of the program is undefined.
}];
}
-def FlagEnumDocs : Documentation {
- let Category = DocCatType;
- let Content = [{
-This attribute can be added to an enumerator to signal to the compiler that it
-is intended to be used as a flag type. This will cause the compiler to assume
-that the range of the type includes all of the values that you can get by
-manipulating bits of the enumerator when issuing warnings.
- }];
-}
-
def MSInheritanceDocs : Documentation {
let Category = DocCatType;
let Heading = "__single_inhertiance, __multiple_inheritance, __virtual_inheritance";
diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td
index 75d40b17a6..5edd3ddbc8 100644
--- a/include/clang/Basic/DiagnosticGroups.td
+++ b/include/clang/Basic/DiagnosticGroups.td
@@ -190,7 +190,6 @@ def OverloadedShiftOpParentheses: DiagGroup<"overloaded-shift-op-parentheses">;
def DanglingElse: DiagGroup<"dangling-else">;
def DanglingField : DiagGroup<"dangling-field">;
def DistributedObjectModifiers : DiagGroup<"distributed-object-modifiers">;
-def FlagEnum : DiagGroup<"flag-enum">;
def InfiniteRecursion : DiagGroup<"infinite-recursion">;
def GNUImaginaryConstant : DiagGroup<"gnu-imaginary-constant">;
def IgnoredQualifiers : DiagGroup<"ignored-qualifiers">;
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 8966c55d09..d2ee3f8b69 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2236,7 +2236,7 @@ def warn_attribute_wrong_decl_type : Warning<
"%0 attribute only applies to %select{functions|unions|"
"variables and functions|functions and methods|parameters|"
"functions, methods and blocks|functions, methods, and classes|"
- "functions, methods, and parameters|classes|enums|variables|methods|"
+ "functions, methods, and parameters|classes|variables|methods|"
"variables, functions and labels|fields and global variables|structs|"
"variables and typedefs|thread-local variables|"
"variables and fields|variables, data members and tag types|"
@@ -4059,9 +4059,6 @@ def ext_enum_too_large : ExtWarn<
def ext_enumerator_increment_too_large : ExtWarn<
"incremented enumerator value %0 is not representable in the "
"largest integer type">, InGroup<EnumTooLarge>;
-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">;
diff --git a/include/clang/Sema/AttributeList.h b/include/clang/Sema/AttributeList.h
index dc85f5d208..5e543a5fa5 100644
--- a/include/clang/Sema/AttributeList.h
+++ b/include/clang/Sema/AttributeList.h
@@ -822,7 +822,6 @@ enum AttributeDeclKind {
ExpectedFunctionMethodOrClass,
ExpectedFunctionMethodOrParameter,
ExpectedClass,
- ExpectedEnum,
ExpectedVariable,
ExpectedMethod,
ExpectedVariableFunctionOrLabel,
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 74efa60c93..bba7c36834 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -7971,12 +7971,6 @@ public:
Expr *SrcExpr, AssignmentAction Action,
bool *Complained = nullptr);
- /// IsValueInFlagEnum - Determine if a value is allowed as part of a flag
- /// enum. If AllowMask is true, then we also allow the complement of a valid
- /// value, to be used as a mask.
- bool IsValueInFlagEnum(const EnumDecl *ED, const llvm::APInt &Val,
- bool AllowMask) const;
-
/// DiagnoseAssignmentEnum - Warn if assignment to enum is a constant
/// integer not in the range of enum values.
void DiagnoseAssignmentEnum(QualType DstType, QualType SrcType,
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 007470344f..a2e5b98d48 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -13519,49 +13519,6 @@ static void CheckForDuplicateEnumValues(Sema &S, ArrayRef<Decl *> Elements,
}
}
-bool
-Sema::IsValueInFlagEnum(const EnumDecl *ED, const llvm::APInt &Val,
- bool AllowMask) const {
- FlagEnumAttr *FEAttr = ED->getAttr<FlagEnumAttr>();
- assert(FEAttr && "looking for value in non-flag enum");
-
- llvm::APInt FlagMask = ~FEAttr->getFlagBits();
- unsigned Width = FlagMask.getBitWidth();
-
- // We will try a zero-extended value for the regular check first.
- llvm::APInt ExtVal = Val.zextOrSelf(Width);
-
- // A value is in a flag enum if either its bits are a subset of the enum's
- // flag bits (the first condition) or we are allowing masks and the same is
- // true of its complement (the second condition). When masks are allowed, we
- // allow the common idiom of ~(enum1 | enum2) to be a valid enum value.
- //
- // While it's true that any value could be used as a mask, the assumption is
- // that a mask will have all of the insignificant bits set. Anything else is
- // likely a logic error.
- if (!(FlagMask & ExtVal))
- return true;
-
- if (AllowMask) {
- // Try a one-extended value instead. This can happen if the enum is wider
- // than the constant used, in C with extensions to allow for wider enums.
- // The mask will still have the correct behaviour, so we give the user the
- // benefit of the doubt.
- //
- // FIXME: This heuristic can cause weird results if the enum was extended
- // to a larger type and is signed, because then bit-masks of smaller types
- // that get extended will fall out of range (e.g. ~0x1u). We currently don't
- // detect that case and will get a false positive for it. In most cases,
- // though, it can be fixed by making it a signed type (e.g. ~0x1), so it may
- // be fine just to accept this as a warning.
- ExtVal |= llvm::APInt::getHighBitsSet(Width, Width - Val.getBitWidth());
- if (!(FlagMask & ~ExtVal))
- return true;
- }
-
- return false;
-}
-
void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
SourceLocation RBraceLoc, Decl *EnumDeclX,
ArrayRef<Decl *> Elements,
@@ -13647,8 +13604,10 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
BestPromotionType = Context.getPromotedIntegerType(BestType);
else
BestPromotionType = BestType;
-
- BestWidth = Context.getIntWidth(BestType);
+ // We don't need to set BestWidth, because BestType is going to be the type
+ // of the enumerators, but we do anyway because otherwise some compilers
+ // warn that it might be used uninitialized.
+ BestWidth = CharWidth;
}
else if (NumNegativeBits) {
// If there is a negative value, figure out the smallest integer type (of
@@ -13713,15 +13672,10 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
}
}
- FlagEnumAttr *FEAttr = Enum->getAttr<FlagEnumAttr>();
- if (FEAttr)
- FEAttr->getFlagBits() = llvm::APInt(BestWidth, 0);
-
// Loop over all of the enumerator constants, changing their types to match
- // the type of the enum if needed. If we have a flag type, we also prepare the
- // FlagBits cache.
- for (auto *D : Elements) {
- auto *ECD = cast_or_null<EnumConstantDecl>(D);
+ // the type of the enum if needed.
+ for (unsigned i = 0, e = Elements.size(); i != e; ++i) {
+ EnumConstantDecl *ECD = cast_or_null<EnumConstantDecl>(Elements[i]);
if (!ECD) continue; // Already issued a diagnostic.
// Standard C says the enumerators have int type, but we allow, as an
@@ -13751,7 +13705,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
// enum-specifier, each enumerator has the type of its
// enumeration.
ECD->setType(EnumType);
- goto flagbits;
+ continue;
} else {
NewTy = BestType;
NewWidth = BestWidth;
@@ -13778,32 +13732,8 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
ECD->setType(EnumType);
else
ECD->setType(NewTy);
-
-flagbits:
- // Check to see if we have a constant with exactly one bit set. Note that x
- // & (x - 1) will be nonzero if and only if x has more than one bit set.
- if (FEAttr) {
- llvm::APInt ExtVal = InitVal.zextOrSelf(BestWidth);
- if (ExtVal != 0 && !(ExtVal & (ExtVal - 1))) {
- FEAttr->getFlagBits() |= ExtVal;
- }
- }
}
- if (FEAttr) {
- for (Decl *D : Elements) {
- EnumConstantDecl *ECD = cast_or_null<EnumConstantDecl>(D);
- if (!ECD) continue; // Already issued a diagnostic.
-
- llvm::APSInt InitVal = ECD->getInitVal();
- if (InitVal != 0 && !IsValueInFlagEnum(Enum, InitVal, true))
- Diag(ECD->getLocation(), diag::warn_flag_enum_constant_out_of_range)
- << ECD << Enum;
- }
- }
-
-
-
Enum->completeDefinition(BestType, BestPromotionType,
NumPositiveBits, NumNegativeBits);
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 17a849ea7a..dcab25e7fe 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -4395,9 +4395,6 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_OptimizeNone:
handleOptimizeNoneAttr(S, D, Attr);
break;
- case AttributeList::AT_FlagEnum:
- handleSimpleAttribute<FlagEnumAttr>(S, D, Attr);
- break;
case AttributeList::AT_Flatten:
handleSimpleAttribute<FlattenAttr>(S, D, Attr);
break;
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 22ed930820..0d1da4540e 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -687,39 +687,26 @@ static void checkCaseValue(Sema &S, SourceLocation Loc, const llvm::APSInt &Val,
}
}
-typedef SmallVector<std::pair<llvm::APSInt, EnumConstantDecl*>, 64> EnumValsTy;
-
/// Returns true if we should emit a diagnostic about this case expression not
/// being a part of the enum used in the switch controlling expression.
-static bool ShouldDiagnoseSwitchCaseNotInEnum(const Sema &S,
+static bool ShouldDiagnoseSwitchCaseNotInEnum(const ASTContext &Ctx,
const EnumDecl *ED,
- const Expr *CaseExpr,
- EnumValsTy::iterator &EI,
- EnumValsTy::iterator &EIEnd,
- const llvm::APSInt &Val) {
- bool FlagType = ED->hasAttr<FlagEnumAttr>();
-
- if (const DeclRefExpr *DRE =
- dyn_cast<DeclRefExpr>(CaseExpr->IgnoreParenImpCasts())) {
+ const Expr *CaseExpr) {
+ // Don't warn if the 'case' expression refers to a static const variable of
+ // the enum type.
+ CaseExpr = CaseExpr->IgnoreParenImpCasts();
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CaseExpr)) {
if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
+ if (!VD->hasGlobalStorage())
+ return true;
QualType VarType = VD->getType();
- QualType EnumType = S.Context.getTypeDeclType(ED);
- if (VD->hasGlobalStorage() && VarType.isConstQualified() &&
- S.Context.hasSameUnqualifiedType(EnumType, VarType))
+ if (!VarType.isConstQualified())
+ return true;
+ QualType EnumType = Ctx.getTypeDeclType(ED);
+ if (Ctx.hasSameUnqualifiedType(EnumType, VarType))
return false;
}
}
-
- if (FlagType) {
- return !S.IsValueInFlagEnum(ED, Val, false);
- } else {
- while (EI != EIEnd && EI->first < Val)
- EI++;
-
- if (EI != EIEnd && EI->first == Val)
- return false;
- }
-
return true;
}
@@ -1059,6 +1046,8 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
// If switch has default case, then ignore it.
if (!CaseListIsErroneous && !HasConstantCond && ET) {
const EnumDecl *ED = ET->getDecl();
+ typedef SmallVector<std::pair<llvm::APSInt, EnumConstantDecl*>, 64>
+ EnumValsTy;
EnumValsTy EnumVals;
// Gather all enum values, set their type and sort them,
@@ -1069,48 +1058,57 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
EnumVals.push_back(std::make_pair(Val, EDI));
}
std::stable_sort(EnumVals.begin(), EnumVals.end(), CmpEnumVals);
- auto EI = EnumVals.begin(), EIEnd =
+ EnumValsTy::iterator EIend =
std::unique(EnumVals.begin(), EnumVals.end(), EqEnumVals);
// See which case values aren't in enum.
+ EnumValsTy::const_iterator EI = EnumVals.begin();
for (CaseValsTy::const_iterator CI = CaseVals.begin();
- CI != CaseVals.end(); CI++) {
- Expr *CaseExpr = CI->second->getLHS();
- if (ShouldDiagnoseSwitchCaseNotInEnum(*this, ED, CaseExpr, EI, EIEnd,
- CI->first))
- Diag(CaseExpr->getExprLoc(), diag::warn_not_in_enum)
- << CondTypeBeforePromotion;
+ CI != CaseVals.end(); CI++) {
+ while (EI != EIend && EI->first < CI->first)
+ EI++;
+ if (EI == EIend || EI->first > CI->first) {
+ Expr *CaseExpr = CI->second->getLHS();
+ if (ShouldDiagnoseSwitchCaseNotInEnum(Context, ED, CaseExpr))
+ Diag(CaseExpr->getExprLoc(), diag::warn_not_in_enum)
+ << CondTypeBeforePromotion;
+ }
}
-
// See which of case ranges aren't in enum
EI = EnumVals.begin();
for (CaseRangesTy::const_iterator RI = CaseRanges.begin();
- RI != CaseRanges.end(); RI++) {
- Expr *CaseExpr = RI->second->getLHS();
- if (ShouldDiagnoseSwitchCaseNotInEnum(*this, ED, CaseExpr, EI, EIEnd,
- RI->first))
- Diag(CaseExpr->getExprLoc(), diag::warn_not_in_enum)
- << CondTypeBeforePromotion;
+ RI != CaseRanges.end() && EI != EIend; RI++) {
+ while (EI != EIend && EI->first < RI->first)
+ EI++;
+
+ if (EI == EIend || EI->first != RI->first) {
+ Expr *CaseExpr = RI->second->getLHS();
+ if (ShouldDiagnoseSwitchCaseNotInEnum(Context, ED, CaseExpr))
+ Diag(CaseExpr->getExprLoc(), diag::warn_not_in_enum)
+ << CondTypeBeforePromotion;
+ }
llvm::APSInt Hi =
RI->second->getRHS()->EvaluateKnownConstInt(Context);
AdjustAPSInt(Hi, CondWidth, CondIsSigned);
-
- CaseExpr = RI->second->getRHS();
- if (ShouldDiagnoseSwitchCaseNotInEnum(*this, ED, CaseExpr, EI, EIEnd,
- Hi))
- Diag(CaseExpr->getExprLoc(), diag::warn_not_in_enum)
- << CondTypeBeforePromotion;
+ while (EI != EIend && EI->first < Hi)
+ EI++;
+ if (EI == EIend || EI->first != Hi) {
+ Expr *CaseExpr = RI->second->getRHS();
+ if (ShouldDiagnoseSwitchCaseNotInEnum(Context, ED, CaseExpr))
+ Diag(CaseExpr->getExprLoc(), diag::warn_not_in_enum)
+ << CondTypeBeforePromotion;
+ }
}
// Check which enum vals aren't in switch
- auto CI = CaseVals.begin();
- auto RI = CaseRanges.begin();
+ CaseValsTy::const_iterator CI = CaseVals.begin();
+ CaseRangesTy::const_iterator RI = CaseRanges.begin();
bool hasCasesNotInSwitch = false;
SmallVector<DeclarationName,8> UnhandledNames;
- for (EI = EnumVals.begin(); EI != EIEnd; EI++){
+ for (EI = EnumVals.begin(); EI != EIend; EI++){
// Drop unneeded case values
while (CI != CaseVals.end() && CI->first < EI->first)
CI++;
@@ -1197,37 +1195,30 @@ Sema::DiagnoseAssignmentEnum(QualType DstType, QualType SrcType,
llvm::APSInt RhsVal = SrcExpr->EvaluateKnownConstInt(Context);
AdjustAPSInt(RhsVal, DstWidth, DstIsSigned);
const EnumDecl *ED = ET->getDecl();
-
- if (ED->hasAttr<FlagEnumAttr>()) {
- if (!IsValueInFlagEnum(ED, RhsVal, true))
- Diag(SrcExpr->getExprLoc(), diag::warn_not_in_enum_assignment)
+ typedef SmallVector<std::pair<llvm::APSInt, EnumConstantDecl *>, 64>
+ EnumValsTy;
+ EnumValsTy EnumVals;
+
+ // Gather all enum values, set their type and sort them,
+ // allowing easier comparison with rhs constant.
+ for (auto *EDI : ED->enumerators()) {
+ llvm::APSInt Val = EDI->getInitVal();
+ AdjustAPSInt(Val, DstWidth, DstIsSigned);
+ EnumVals.push_back(std::make_pair(Val, EDI));
+ }
+ if (EnumVals.empty())
+ return;
+ std::stable_sort(EnumVals.begin(), EnumVals.end(), CmpEnumVals);
+ EnumValsTy::iterator EIend =
+ std::unique(EnumVals.begin(), EnumVals.end(), EqEnumVals);
+
+ // See which values aren't in the enum.
+ EnumValsTy::const_iterator EI = EnumVals.begin();
+ while (EI != EIend && EI->first < RhsVal)
+ EI++;
+ if (EI == EIend || EI->first != RhsVal) {
+ Diag(SrcExpr->getExprLoc(), diag::warn_not_in_enum_assignment)
<< DstType.getUnqualifiedType();
- } else {
- typedef SmallVector<std::pair<llvm::APSInt, EnumConstantDecl *>, 64>
- EnumValsTy;
- EnumValsTy EnumVals;
-
- // Gather all enum values, set their type and sort them,
- // allowing easier comparison with rhs constant.
- for (auto *EDI : ED->enumerators()) {
- llvm::APSInt Val = EDI->getInitVal();
- AdjustAPSInt(Val, DstWidth, DstIsSigned);
- EnumVals.push_back(std::make_pair(Val, EDI));
- }
- if (EnumVals.empty())
- return;
- std::stable_sort(EnumVals.begin(), EnumVals.end(), CmpEnumVals);
- EnumValsTy::iterator EIend =
- std::unique(EnumVals.begin(), EnumVals.end(), EqEnumVals);
-
- // See which values aren't in the enum.
- EnumValsTy::const_iterator EI = EnumVals.begin();
- while (EI != EIend && EI->first < RhsVal)
- EI++;
- if (EI == EIend || EI->first != RhsVal) {
- Diag(SrcExpr->getExprLoc(), diag::warn_not_in_enum_assignment)
- << DstType.getUnqualifiedType();
- }
}
}
}
diff --git a/test/Sema/attr-flag-enum.c b/test/Sema/attr-flag-enum.c
deleted file mode 100644
index a53c1dc8e7..0000000000
--- a/test/Sema/attr-flag-enum.c
+++ /dev/null
@@ -1,73 +0,0 @@
-// RUN: %clang_cc1 -verify -fsyntax-only -std=c11 -Wassign-enum %s
-
-enum __attribute__((flag_enum)) flag {
- ea = 0x1,
- eb = 0x2,
- ec = 0x8,
-};
-
-enum __attribute__((flag_enum)) flag2 {
- ga = 0x1,
- gb = 0x4,
-
- gc = 0x5, // no-warning
- gd = 0x7, // expected-warning {{enumeration value 'gd' is out of range}}
- ge = ~0x2, // expected-warning {{enumeration value 'ge' is out of range}}
- gf = ~0x4, // no-warning
- gg = ~0x1, // no-warning
- gh = ~0x5, // no-warning
- gi = ~0x11, // expected-warning {{enumeration value 'gi' is out of range}}
-};
-
-enum __attribute__((flag_enum)) flag3 {
- fa = 0x1,
- fb = ~0x1u, // no-warning
-};
-
-// What happens here is that ~0x2 is negative, and so the enum must be signed.
-// But ~0x1u is unsigned and has the high bit set, so the enum must be 64-bit.
-// The result is that ~0x1u does not have high bits set, and so it is considered
-// to be an invalid value. See Sema::IsValueInFlagEnum in SemaDecl.cpp for more
-// discussion.
-enum __attribute__((flag_enum)) flag4 {
- ha = 0x1,
- hb = 0x2,
-
- hc = ~0x1u, // expected-warning {{enumeration value 'hc' is out of range}}
- hd = ~0x2, // no-warning
-};
-
-void f(void) {
- enum flag e = 0; // no-warning
- e = 0x1; // no-warning
- e = 0x3; // no-warning
- e = 0xa; // no-warning
- e = 0x4; // expected-warning {{integer constant not in range of enumerated type}}
- e = 0xf; // expected-warning {{integer constant not in range of enumerated type}}
- e = ~0; // no-warning
- e = ~0x1; // no-warning
- e = ~0x2; // no-warning
- e = ~0x3; // no-warning
- e = ~0x4; // expected-warning {{integer constant not in range of enumerated type}}
-
- switch (e) {
- case 0: break; // no-warning
- case 0x1: break; // no-warning
- case 0x3: break; // no-warning
- case 0xa: break; // no-warning
- case 0x4: break; // expected-warning {{case value not in enumerated type}}
- case 0xf: break; // expected-warning {{case value not in enumerated type}}
- case ~0: break; // expected-warning {{case value not in enumerated type}}
- case ~0x1: break; // expected-warning {{case value not in enumerated type}}
- case ~0x2: break; // expected-warning {{case value not in enumerated type}}
- case ~0x3: break; // expected-warning {{case value not in enumerated type}}
- case ~0x4: break; // expected-warning {{case value not in enumerated type}}
- default: break;
- }
-
- enum flag2 f = ~0x1; // no-warning
- f = ~0x1u; // no-warning
-
- enum flag4 h = ~0x1; // no-warning
- h = ~0x1u; // expected-warning {{integer constant not in range of enumerated type}}
-}
diff --git a/test/SemaCXX/attr-flag-enum-reject.cpp b/test/SemaCXX/attr-flag-enum-reject.cpp
deleted file mode 100644
index f28d60c0c2..0000000000
--- a/test/SemaCXX/attr-flag-enum-reject.cpp
+++ /dev/null
@@ -1,4 +0,0 @@
-// RUN: %clang_cc1 -verify -fsyntax-only -x c++ -Wassign-enum %s
-
-enum __attribute__((flag_enum)) flag { // expected-warning {{ignored}}
-};
diff --git a/utils/TableGen/ClangAttrEmitter.cpp b/utils/TableGen/ClangAttrEmitter.cpp
index a73be2e081..5dd3f7e4af 100644
--- a/utils/TableGen/ClangAttrEmitter.cpp
+++ b/utils/TableGen/ClangAttrEmitter.cpp
@@ -2185,8 +2185,7 @@ static std::string CalculateDiagnostic(const Record &S) {
Namespace = 1U << 11,
Field = 1U << 12,
CXXMethod = 1U << 13,
- ObjCProtocol = 1U << 14,
- Enum = 1U << 15
+ ObjCProtocol = 1U << 14
};
uint32_t SubMask = 0;
@@ -2220,7 +2219,6 @@ static std::string CalculateDiagnostic(const Record &S) {
.Case("Namespace", Namespace)
.Case("Field", Field)
.Case("CXXMethod", CXXMethod)
- .Case("Enum", Enum)
.Default(0);
if (!V) {
// Something wasn't in our mapping, so be helpful and let the developer
@@ -2239,7 +2237,6 @@ static std::string CalculateDiagnostic(const Record &S) {
case Var: return "ExpectedVariable";
case Param: return "ExpectedParameter";
case Class: return "ExpectedClass";
- case Enum: return "ExpectedEnum";
case CXXMethod:
// FIXME: Currently, this maps to ExpectedMethod based on existing code,
// but should map to something a bit more accurate at some point.
@@ -2393,8 +2390,6 @@ static std::string GenerateLangOptRequirements(const Record &R,
std::string FnName = "check", Test;
for (auto I = LangOpts.begin(), E = LangOpts.end(); I != E; ++I) {
std::string Part = (*I)->getValueAsString("Name");
- if ((*I)->getValueAsBit("Negated"))
- Test += "!";
Test += "S.LangOpts." + Part;
if (I + 1 != E)
Test += " || ";