aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaDecl.cpp
diff options
context:
space:
mode:
authorEli Friedman <eli.friedman@gmail.com>2009-06-01 09:24:59 +0000
committerEli Friedman <eli.friedman@gmail.com>2009-06-01 09:24:59 +0000
commitbc4e29f307f86ddbc2f31d9530da79ad9b0c6b7b (patch)
tree27c814f8c39d39cc6c823b98a406b768ac2bf4e1 /lib/Sema/SemaDecl.cpp
parentc13f9f037324d49bc8df880000a27d2b0e33d69c (diff)
PR4287: allow a variadic prototype to make a subsequent K&R style
definition variadic. I'm not completely sure it's legal, but the standard can be interpreted as making it legal, and gcc seems to think it's legal, so I didn't add an extension warning. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@72689 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaDecl.cpp')
-rw-r--r--lib/Sema/SemaDecl.cpp25
1 files changed, 14 insertions, 11 deletions
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 9c650e61e7..959154c4ec 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -765,6 +765,11 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
// 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 a variadic prototype is followed by a non-variadic K&R definition,
+ // the K&R definition becomes variadic. This is sort of an edge case, but
+ // it's legal per the standard depending on how you read C99 6.7.5.3p15 and
+ // C99 6.9.1p8.
if (!getLangOptions().CPlusPlus &&
Old->hasPrototype() && !New->hasPrototype() &&
New->getType()->getAsFunctionProtoType() &&
@@ -777,12 +782,11 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
= New->getType()->getAsFunctionProtoType();
// Determine whether this is the GNU C extension.
- bool GNUCompatible =
- Context.typesAreCompatible(OldProto->getResultType(),
- NewProto->getResultType()) &&
- (OldProto->isVariadic() == NewProto->isVariadic());
+ QualType MergedReturn = Context.mergeTypes(OldProto->getResultType(),
+ NewProto->getResultType());
+ bool LooseCompatible = !MergedReturn.isNull();
for (unsigned Idx = 0, End = Old->getNumParams();
- GNUCompatible && Idx != End; ++Idx) {
+ LooseCompatible && Idx != End; ++Idx) {
ParmVarDecl *OldParm = Old->getParamDecl(Idx);
ParmVarDecl *NewParm = New->getParamDecl(Idx);
if (Context.typesAreCompatible(OldParm->getType(),
@@ -795,10 +799,10 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
Warnings.push_back(Warn);
ArgTypes.push_back(NewParm->getType());
} else
- GNUCompatible = false;
+ LooseCompatible = false;
}
- if (GNUCompatible) {
+ if (LooseCompatible) {
for (unsigned Warn = 0; Warn < Warnings.size(); ++Warn) {
Diag(Warnings[Warn].NewParm->getLocation(),
diag::ext_param_promoted_not_compatible_with_prototype)
@@ -808,10 +812,9 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
diag::note_previous_declaration);
}
- New->setType(Context.getFunctionType(NewProto->getResultType(),
- &ArgTypes[0], ArgTypes.size(),
- NewProto->isVariadic(),
- NewProto->getTypeQuals()));
+ New->setType(Context.getFunctionType(MergedReturn, &ArgTypes[0],
+ ArgTypes.size(),
+ OldProto->isVariadic(), 0));
return MergeCompatibleFunctionDecls(New, Old);
}