Author: d0k Date: Sat Aug 20 11:51:33 2016 New Revision: 279374 URL: http://llvm.org/viewvc/llvm-project?rev=279374&view=rev Log: [Sema] Don't crash on scanf on forward-declared enums.
This is valid in GNU C, which allows pointers to incomplete enums. GCC just pretends that the underlying type is 'int' in those cases, follow that behavior. Modified: cfe/trunk/lib/Analysis/FormatString.cpp cfe/trunk/lib/Analysis/ScanfFormatString.cpp cfe/trunk/test/Sema/format-strings-enum.c Modified: cfe/trunk/lib/Analysis/FormatString.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/FormatString.cpp?rev=279374&r1=279373&r2=279374&view=diff ============================================================================== --- cfe/trunk/lib/Analysis/FormatString.cpp (original) +++ cfe/trunk/lib/Analysis/FormatString.cpp Sat Aug 20 11:51:33 2016 @@ -310,8 +310,13 @@ ArgType::matchesType(ASTContext &C, Qual return Match; case AnyCharTy: { - if (const EnumType *ETy = argTy->getAs<EnumType>()) + if (const EnumType *ETy = argTy->getAs<EnumType>()) { + // If the enum is incomplete we know nothing about the underlying type. + // Assume that it's 'int'. + if (!ETy->getDecl()->isComplete()) + return NoMatch; argTy = ETy->getDecl()->getIntegerType(); + } if (const BuiltinType *BT = argTy->getAs<BuiltinType>()) switch (BT->getKind()) { @@ -327,8 +332,14 @@ ArgType::matchesType(ASTContext &C, Qual } case SpecificTy: { - if (const EnumType *ETy = argTy->getAs<EnumType>()) - argTy = ETy->getDecl()->getIntegerType(); + if (const EnumType *ETy = argTy->getAs<EnumType>()) { + // If the enum is incomplete we know nothing about the underlying type. + // Assume that it's 'int'. + if (!ETy->getDecl()->isComplete()) + argTy = C.IntTy; + else + argTy = ETy->getDecl()->getIntegerType(); + } argTy = C.getCanonicalType(argTy).getUnqualifiedType(); if (T == argTy) Modified: cfe/trunk/lib/Analysis/ScanfFormatString.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/ScanfFormatString.cpp?rev=279374&r1=279373&r2=279374&view=diff ============================================================================== --- cfe/trunk/lib/Analysis/ScanfFormatString.cpp (original) +++ cfe/trunk/lib/Analysis/ScanfFormatString.cpp Sat Aug 20 11:51:33 2016 @@ -418,8 +418,12 @@ bool ScanfSpecifier::fixType(QualType QT QualType PT = QT->getPointeeType(); // If it's an enum, get its underlying type. - if (const EnumType *ETy = PT->getAs<EnumType>()) + if (const EnumType *ETy = PT->getAs<EnumType>()) { + // Don't try to fix incomplete enums. + if (!ETy->getDecl()->isComplete()) + return false; PT = ETy->getDecl()->getIntegerType(); + } const BuiltinType *BT = PT->getAs<BuiltinType>(); if (!BT) Modified: cfe/trunk/test/Sema/format-strings-enum.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/format-strings-enum.c?rev=279374&r1=279373&r2=279374&view=diff ============================================================================== --- cfe/trunk/test/Sema/format-strings-enum.c (original) +++ cfe/trunk/test/Sema/format-strings-enum.c Sat Aug 20 11:51:33 2016 @@ -11,6 +11,7 @@ #endif EXTERN_C int printf(const char *,...); +EXTERN_C int scanf(const char *, ...); typedef enum { Constant = 0 } TestEnum; // Note that in C, the type of 'Constant' is 'int'. In C++ it is 'TestEnum'. @@ -34,3 +35,18 @@ void testLong(LongEnum input) { printf("%lu", input); printf("%lu", LongConstant); } + +#ifndef __cplusplus +// GNU C allows forward declaring enums. +extern enum forward_declared *fwd; + +void forward_enum() { + printf("%u", fwd); // expected-warning{{format specifies type 'unsigned int' but the argument has type 'enum forward_declared *}} + printf("%p", fwd); + + scanf("%c", fwd); // expected-warning{{format specifies type 'char *' but the argument has type 'enum forward_declared *}} + scanf("%u", fwd); + scanf("%lu", fwd); // expected-warning{{format specifies type 'unsigned long *' but the argument has type 'enum forward_declared *}} + scanf("%p", fwd); // expected-warning{{format specifies type 'void **' but the argument has type 'enum forward_declared *}} +} +#endif _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits