From 98a017e0587e918c53184cc9dbb3764a99f9e372 Mon Sep 17 00:00:00 2001 From: Aaron Ballman Date: Sun, 12 Feb 2017 19:24:47 +0000 Subject: [PATCH] Revert r294910 and recommit r294861 and r294862 with a target triple to hopefully appease the bots. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@294911 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/Type.h | 39 ++++++++++++++++++++++++++++++ include/clang/AST/TypeLoc.h | 25 +++++++++++++++++++ lib/Sema/SemaDecl.cpp | 9 ++++--- test/Sema/knr-def-call.c | 14 ++++++++--- test/Sema/warn-strict-prototypes.c | 9 +++++-- 5 files changed, 86 insertions(+), 10 deletions(-) diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 0a50b618c9..0db0905cba 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -1888,6 +1888,13 @@ public: /// immediately following this class. template const T *getAs() const; + /// Member-template getAsAdjusted. Look through specific kinds + /// of sugar (parens, attributes, etc) for an instance of \. + /// This is used when you need to walk over sugar nodes that represent some + /// kind of type adjustment from a type that was written as a \ + /// to another type that is still canonically a \. + template const T *getAsAdjusted() const; + /// A variant of getAs<> for array types which silently discards /// qualifiers from the outermost type. const ArrayType *getAsArrayTypeUnsafe() const; @@ -6008,6 +6015,38 @@ template const T *Type::getAs() const { return cast(getUnqualifiedDesugaredType()); } +template const T *Type::getAsAdjusted() const { + static_assert(!TypeIsArrayType::value, "ArrayType cannot be used with getAsAdjusted!"); + + // If this is directly a T type, return it. + if (const T *Ty = dyn_cast(this)) + return Ty; + + // If the canonical form of this type isn't the right kind, reject it. + if (!isa(CanonicalType)) + return nullptr; + + // Strip off type adjustments that do not modify the underlying nature of the + // type. + const Type *Ty = this; + while (Ty) { + if (const auto *A = dyn_cast(Ty)) + Ty = A->getModifiedType().getTypePtr(); + else if (const auto *E = dyn_cast(Ty)) + Ty = E->desugar().getTypePtr(); + else if (const auto *P = dyn_cast(Ty)) + Ty = P->desugar().getTypePtr(); + else if (const auto *A = dyn_cast(Ty)) + Ty = A->desugar().getTypePtr(); + else + break; + } + + // Just because the canonical type is correct does not mean we can use cast<>, + // since we may not have stripped off all the sugar down to the base type. + return dyn_cast(Ty); +} + inline const ArrayType *Type::getAsArrayTypeUnsafe() const { // If this is directly an array type, return it. if (const ArrayType *arr = dyn_cast(this)) diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h index a10b9792d9..525f848a9f 100644 --- a/include/clang/AST/TypeLoc.h +++ b/include/clang/AST/TypeLoc.h @@ -70,6 +70,13 @@ public: return t; } + /// \brief Convert to the specified TypeLoc type, returning a null TypeLoc if + /// this TypeLock is not of the desired type. It will consider type + /// adjustments from a type that wad written as a T to another type that is + /// still canonically a T (ignores parens, attributes, elaborated types, etc). + template + T getAsAdjusted() const; + /// The kinds of TypeLocs. Equivalent to the Type::TypeClass enum, /// except it also defines a Qualified enum that corresponds to the /// QualifiedLoc class. @@ -2188,6 +2195,24 @@ public: QualType getInnerType() const { return this->getTypePtr()->getElementType(); } }; + +template +inline T TypeLoc::getAsAdjusted() const { + TypeLoc Cur = *this; + while (!T::isKind(Cur)) { + if (auto PTL = Cur.getAs()) + Cur = PTL.getInnerLoc(); + else if (auto ATL = Cur.getAs()) + Cur = ATL.getModifiedLoc(); + else if (auto ETL = Cur.getAs()) + Cur = ETL.getNamedTypeLoc(); + else if (auto ATL = Cur.getAs()) + Cur = ATL.getOriginalLoc(); + else + break; + } + return Cur.getAs(); +} } #endif diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 5f98d4505f..bc4611cb06 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -7564,11 +7564,12 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D, // Determine whether the function was written with a // prototype. This true when: // - there is a prototype in the declarator, or - // - the type R of the function is some kind of typedef or other reference - // to a type name (which eventually refers to a function type). + // - the type R of the function is some kind of typedef or other non- + // attributed reference to a type name (which eventually refers to a + // function type). bool HasPrototype = (D.isFunctionDeclarator() && D.getFunctionTypeInfo().hasPrototype) || - (!isa(R.getTypePtr()) && R->isFunctionProtoType()); + (!R->getAsAdjusted() && R->isFunctionProtoType()); NewFD = FunctionDecl::Create(SemaRef.Context, DC, D.getLocStart(), NameInfo, R, @@ -12104,7 +12105,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, !LangOpts.CPlusPlus) { TypeSourceInfo *TI = FD->getTypeSourceInfo(); TypeLoc TL = TI->getTypeLoc(); - FunctionTypeLoc FTL = TL.castAs(); + FunctionTypeLoc FTL = TL.getAsAdjusted(); Diag(FTL.getLParenLoc(), diag::warn_strict_prototypes) << 1; } } diff --git a/test/Sema/knr-def-call.c b/test/Sema/knr-def-call.c index 80ad0d820b..2bd4a79fd0 100644 --- a/test/Sema/knr-def-call.c +++ b/test/Sema/knr-def-call.c @@ -1,13 +1,13 @@ -// RUN: %clang_cc1 -Wconversion -Wliteral-conversion -fsyntax-only -verify %s +// RUN: %clang_cc1 -triple i386-pc-unknown -Wconversion -Wliteral-conversion -fsyntax-only -verify %s // C DR #316, PR 3626. void f0(a, b, c, d) int a,b,c,d; {} -void t0(void) { +void t0(void) { f0(1); // expected-warning{{too few arguments}} } void f1(a, b) int a, b; {} -void t1(void) { +void t1(void) { f1(1, 2, 3); // expected-warning{{too many arguments}} } @@ -30,7 +30,7 @@ char *rindex(s, c) // PR8314 void proto(int); -void proto(x) +void proto(x) int x; { } @@ -39,3 +39,9 @@ void use_proto() { proto(42.1); // expected-warning{{implicit conversion from 'double' to 'int' changes value from 42.1 to 42}} (&proto)(42.1); // expected-warning{{implicit conversion from 'double' to 'int' changes value from 42.1 to 42}} } + +// PR31020 +void func(short d) __attribute__((cdecl)); // expected-note{{previous declaration is here}} +void __attribute__((cdecl)) func(d) + short d; // expected-warning{{promoted type 'int' of K&R function parameter is not compatible with the parameter type 'short' declared in a previous prototype}} +{} diff --git a/test/Sema/warn-strict-prototypes.c b/test/Sema/warn-strict-prototypes.c index 496579c1f6..a28f57d48c 100644 --- a/test/Sema/warn-strict-prototypes.c +++ b/test/Sema/warn-strict-prototypes.c @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -fsyntax-only -Wstrict-prototypes -verify %s -// RUN: %clang_cc1 -fsyntax-only -Wstrict-prototypes -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s +// RUN: %clang_cc1 -triple i386-pc-unknown -fsyntax-only -Wstrict-prototypes -verify %s +// RUN: %clang_cc1 -triple i386-pc-unknown -fsyntax-only -Wstrict-prototypes -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s // function declaration with unspecified params void foo1(); // expected-warning {{this function declaration is not a prototype}} @@ -60,3 +60,8 @@ void foo10(p, p2) void *p; {} // expected-warning {{old-style function definitio // K&R function definition with previous prototype declared is not diagnosed. void foo11(int p, int p2); void foo11(p, p2) int p; int p2; {} + +// PR31020 +void __attribute__((cdecl)) foo12(d) // expected-warning {{this old-style function definition is not preceded by a prototype}} + short d; +{} -- 2.40.0