]> granicus.if.org Git - clang/commitdiff
Reapply: Silence false positive diagnostics regarding passing an object of enumeratio...
authorAaron Ballman <aaron@aaronballman.com>
Thu, 15 Sep 2016 18:07:51 +0000 (18:07 +0000)
committerAaron Ballman <aaron@aaronballman.com>
Thu, 15 Sep 2016 18:07:51 +0000 (18:07 +0000)
The underlying type for an enumeration in C is either char, signed int, or unsigned int. In the case the underlying type is chosen to be char (such as when passing -fshort-enums or using __attribute__((packed)) on the enum declaration), the enumeration can result in undefined behavior. However, when the underlying type is signed int or unsigned int (or long long as an extension), there is no undefined behavior because the types are compatible. This patch silences diagnostics for the latter while retaining the diagnostics for the former.

This patch addresses PR29140.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@281632 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaChecking.cpp
test/Sema/varargs.c

index 81dc23724e929f7f36673aa425f2f52f33e6017e..f3f204ffa04ee7389a0e552e073fbd3ae7e9dbec 100644 (file)
@@ -3240,8 +3240,17 @@ bool Sema::SemaBuiltinVAStartImpl(CallExpr *TheCall) {
     Diag(TheCall->getArg(1)->getLocStart(),
          diag::warn_second_arg_of_va_start_not_last_named_param);
   else if (IsCRegister || Type->isReferenceType() ||
-           Type->isPromotableIntegerType() ||
-           Type->isSpecificBuiltinType(BuiltinType::Float)) {
+           Type->isSpecificBuiltinType(BuiltinType::Float) || [=] {
+             // Promotable integers are UB, but enumerations need a bit of
+             // extra checking to see what their promotable type actually is.
+             if (!Type->isPromotableIntegerType())
+               return false;
+             if (!Type->isEnumeralType())
+               return true;
+             const EnumDecl *ED = Type->getAs<EnumType>()->getDecl();
+             return !(ED &&
+                      Context.typesAreCompatible(ED->getPromotionType(), Type));
+           }()) {
     unsigned Reason = 0;
     if (Type->isReferenceType())  Reason = 1;
     else if (IsCRegister)         Reason = 2;
index 457d84c212f7d94304f82399daa6e5bab54e1b58..25a5c72c42e3c1466f0dae8aa676b73e03f525e9 100644 (file)
@@ -1,5 +1,6 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s -triple i386-pc-unknown
 // RUN: %clang_cc1 -fsyntax-only -verify %s -triple x86_64-apple-darwin9
+// RUN: %clang_cc1 -fsyntax-only -fms-compatibility -DMS -verify %s -triple x86_64-pc-win32
 
 void f1(int a)
 {
@@ -94,3 +95,20 @@ void f12(register int i, ...) {  // expected-note {{parameter of type 'int' is d
   __builtin_va_start(ap, i); // expected-warning {{passing a parameter declared with the 'register' keyword to 'va_start' has undefined behavior}}
   __builtin_va_end(ap);
 }
+
+enum __attribute__((packed)) E1 {
+  one1
+};
+
+void f13(enum E1 e, ...) {
+  __builtin_va_list va;
+  __builtin_va_start(va, e);
+#ifndef MS
+  // In Microsoft compatibility mode, all enum types are int, but in
+  // non-ms-compatibility mode, this enumeration type will undergo default
+  // argument promotions.
+  // expected-note@-7 {{parameter of type 'enum E1' is declared here}}
+  // expected-warning@-6 {{passing an object that undergoes default argument promotion to 'va_start' has undefined behavior}}
+#endif
+  __builtin_va_end(va);
+}