[cfe-commits] r66301 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.def lib/Sema/SemaDecl.cpp test/Sema/function-redecl.c test/Sema/knr-def-call.c
Douglas Gregor
dgregor at apple.com
Fri Mar 6 14:43:54 PST 2009
Author: dgregor
Date: Fri Mar 6 16:43:54 2009
New Revision: 66301
URL: http://llvm.org/viewvc/llvm-project?rev=66301&view=rev
Log:
Implement GNU C semantics for K&R function definitions that follow a
prototype of the same function, where the promoted parameter types in
the K&R definition are not compatible with the types in the
prototype. Fixes PR2821.
Modified:
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/test/Sema/function-redecl.c
cfe/trunk/test/Sema/knr-def-call.c
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def?rev=66301&r1=66300&r2=66301&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def Fri Mar 6 16:43:54 2009
@@ -470,6 +470,9 @@
DIAG(err_param_default_argument_nonfunc, ERROR,
"default arguments can only be specified for parameters in a function"
" declaration")
+DIAG(ext_param_promoted_not_compatible_with_prototype, EXTWARN,
+ "promoted type %0 of K&R function parameter is not compatible with the "
+ "parameter type %1 declared in a previous prototype")
// C++ Overloading Semantic Analysis.
DIAG(err_ovl_diff_return_type, ERROR,
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=66301&r1=66300&r2=66301&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Fri Mar 6 16:43:54 2009
@@ -510,6 +510,14 @@
Old->invalidateAttrs();
}
+/// Used in MergeFunctionDecl to keep track of function parameters in
+/// C.
+struct GNUCompatibleParamWarning {
+ ParmVarDecl *OldParm;
+ ParmVarDecl *NewParm;
+ QualType PromotedType;
+};
+
/// MergeFunctionDecl - We just parsed a function 'New' from
/// declarator D which has the same name and scope as a previous
/// declaration 'Old'. Figure out how to resolve this situation,
@@ -617,10 +625,11 @@
// duplicate function decls like "void f(int); void f(enum X);" properly.
if (!getLangOptions().CPlusPlus &&
Context.typesAreCompatible(OldQType, NewQType)) {
+ const FunctionType *OldFuncType = OldQType->getAsFunctionType();
const FunctionType *NewFuncType = NewQType->getAsFunctionType();
const FunctionProtoType *OldProto = 0;
if (isa<FunctionNoProtoType>(NewFuncType) &&
- (OldProto = OldQType->getAsFunctionProtoType())) {
+ (OldProto = dyn_cast<FunctionProtoType>(OldFuncType))) {
// The old declaration provided a function prototype, but the
// new declaration does not. Merge in the prototype.
llvm::SmallVector<QualType, 16> ParamTypes(OldProto->arg_type_begin(),
@@ -647,10 +656,69 @@
}
New->setParams(Context, &Params[0], Params.size());
+ }
+
+ return MergeCompatibleFunctionDecls(New, Old);
+ }
+ // GNU C permits a K&R definition to follow a prototype declaration
+ // if the declared types of the parameters in the K&R definition
+ // match the types in the prototype declaration, even when the
+ // promoted types of the parameters from the K&R definition differ
+ // from the types in the prototype. GCC then keeps the types from
+ // the prototype.
+ if (!getLangOptions().CPlusPlus &&
+ !getLangOptions().NoExtensions &&
+ Old->hasPrototype() && !New->hasPrototype() &&
+ New->getType()->getAsFunctionProtoType() &&
+ Old->getNumParams() == New->getNumParams()) {
+ llvm::SmallVector<QualType, 16> ArgTypes;
+ llvm::SmallVector<GNUCompatibleParamWarning, 16> Warnings;
+ const FunctionProtoType *OldProto
+ = Old->getType()->getAsFunctionProtoType();
+ const FunctionProtoType *NewProto
+ = New->getType()->getAsFunctionProtoType();
+
+ // Determine whether this is the GNU C extension.
+ bool GNUCompatible =
+ Context.typesAreCompatible(OldProto->getResultType(),
+ NewProto->getResultType()) &&
+ (OldProto->isVariadic() == NewProto->isVariadic());
+ for (unsigned Idx = 0, End = Old->getNumParams();
+ GNUCompatible && Idx != End; ++Idx) {
+ ParmVarDecl *OldParm = Old->getParamDecl(Idx);
+ ParmVarDecl *NewParm = New->getParamDecl(Idx);
+ if (Context.typesAreCompatible(OldParm->getType(),
+ NewProto->getArgType(Idx))) {
+ ArgTypes.push_back(NewParm->getType());
+ } else if (Context.typesAreCompatible(OldParm->getType(),
+ NewParm->getType())) {
+ GNUCompatibleParamWarning Warn
+ = { OldParm, NewParm, NewProto->getArgType(Idx) };
+ Warnings.push_back(Warn);
+ ArgTypes.push_back(NewParm->getType());
+ } else
+ GNUCompatible = false;
+ }
+
+ if (GNUCompatible) {
+ for (unsigned Warn = 0; Warn < Warnings.size(); ++Warn) {
+ Diag(Warnings[Warn].NewParm->getLocation(),
+ diag::ext_param_promoted_not_compatible_with_prototype)
+ << Warnings[Warn].PromotedType
+ << Warnings[Warn].OldParm->getType();
+ Diag(Warnings[Warn].OldParm->getLocation(),
+ diag::note_previous_declaration);
+ }
+
+ New->setType(Context.getFunctionType(NewProto->getResultType(),
+ &ArgTypes[0], ArgTypes.size(),
+ NewProto->isVariadic(),
+ NewProto->getTypeQuals()));
+ return MergeCompatibleFunctionDecls(New, Old);
}
- return MergeCompatibleFunctionDecls(New, Old);
+ // Fall through to diagnose conflicting types.
}
// A function that has already been declared has been redeclared or defined
Modified: cfe/trunk/test/Sema/function-redecl.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/function-redecl.c?rev=66301&r1=66300&r2=66301&view=diff
==============================================================================
--- cfe/trunk/test/Sema/function-redecl.c (original)
+++ cfe/trunk/test/Sema/function-redecl.c Fri Mar 6 16:43:54 2009
@@ -93,3 +93,16 @@
}
static float outer8(float); // okay
+
+enum e { e1, e2 };
+
+// GNU extension: prototypes and K&R function definitions
+int isroot(short x, // expected-note{{previous declaration is here}}
+ enum e);
+
+int isroot(x, y)
+ short x; // expected-warning{{promoted type 'int' of K&R function parameter is not compatible with the parameter type 'short' declared in a previous prototype}}
+ unsigned int y;
+{
+ return x == 1;
+}
Modified: cfe/trunk/test/Sema/knr-def-call.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/knr-def-call.c?rev=66301&r1=66300&r2=66301&view=diff
==============================================================================
--- cfe/trunk/test/Sema/knr-def-call.c (original)
+++ cfe/trunk/test/Sema/knr-def-call.c Fri Mar 6 16:43:54 2009
@@ -8,7 +8,7 @@
void t1(void) { f1(1, 2, 3); }
void f2(float); // expected-note{{previous declaration is here}}
-void f2(x) float x; { } // expected-error{{conflicting types for 'f2'}}
+void f2(x) float x; { } // expected-warning{{promoted type 'double' of K&R function parameter is not compatible with the parameter type 'float' declared in a previous prototype}}
typedef void (*f3)(void);
f3 t3(int b) { return b? f0 : f1; } // okay
More information about the cfe-commits
mailing list