[cfe-commits] r49370 - /cfe/trunk/lib/Sema/SemaDeclCXX.cpp

Chris Lattner sabre at nondot.org
Mon Apr 7 22:04:31 PDT 2008


Author: lattner
Date: Tue Apr  8 00:04:30 2008
New Revision: 49370

URL: http://llvm.org/viewvc/llvm-project?rev=49370&view=rev
Log:
Add support for C++ default arguments, and rework Parse-Sema 
interaction for function parameters, fixing PR2046.

Patch by Doug Gregor!

Added:
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp

Added: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=49370&view=auto

==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (added)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Tue Apr  8 00:04:30 2008
@@ -0,0 +1,158 @@
+//===------ SemaDeclCXX.cpp - Semantic Analysis for C++ Declarations ------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file implements semantic analysis for C++ declarations.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Sema.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/Type.h"
+#include "llvm/ADT/OwningPtr.h"
+
+using namespace clang;
+
+void
+Sema::ActOnParamDefaultArgument(DeclTy *param, SourceLocation EqualLoc, 
+                                ExprTy *defarg) {
+  ParmVarDecl *Param = (ParmVarDecl *)param;
+  llvm::OwningPtr<Expr> DefaultArg((Expr *)defarg);
+  QualType ParamType = Param->getType();
+
+  // Default arguments are only permitted in C++
+  if (!getLangOptions().CPlusPlus) {
+    Diag(EqualLoc, diag::err_param_default_argument, 
+         DefaultArg->getSourceRange());
+    return;
+  }
+
+  // C++ [dcl.fct.default]p5
+  //   A default argument expression is implicitly converted (clause
+  //   4) to the parameter type. The default argument expression has
+  //   the same semantic constraints as the initializer expression in
+  //   a declaration of a variable of the parameter type, using the
+  //   copy-initialization semantics (8.5).
+  //
+  // FIXME: CheckSingleAssignmentConstraints has the wrong semantics
+  // for C++ (since we want copy-initialization, not copy-assignment),
+  // but we don't have the right semantics implemented yet. Because of
+  // this, our error message is also very poor.
+  QualType DefaultArgType = DefaultArg->getType();   
+  Expr *DefaultArgPtr = DefaultArg.get();
+  AssignConvertType ConvTy = CheckSingleAssignmentConstraints(ParamType,
+                                                              DefaultArgPtr);
+  if (DefaultArgPtr != DefaultArg.get()) {
+    DefaultArg.take();
+    DefaultArg.reset(DefaultArgPtr);
+  }
+  if (DiagnoseAssignmentResult(ConvTy, DefaultArg->getLocStart(), 
+                               ParamType, DefaultArgType, DefaultArg.get(), 
+                               "in default argument")) {
+    return;
+  }
+
+  // FIXME: C++ [dcl.fct.default]p3
+  //   A default argument expression shall be specified only in the
+  //   parameter-declaration-clause of a function declaration or in a
+  //   template-parameter (14.1). It shall not be specified for a
+  //   parameter pack. If it is specified in a
+  //   parameter-declaration-clause, it shall not occur within a
+  //   declarator or abstract-declarator of a parameter-declaration.
+
+  // Okay: add the default argument to the parameter
+  Param->setDefaultArg(DefaultArg.take());
+}
+
+// MergeCXXFunctionDecl - Merge two declarations of the same C++
+// function, once we already know that they have the same
+// type. Subroutine of MergeFunctionDecl.
+FunctionDecl * 
+Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) {
+  // C++ [dcl.fct.default]p4:
+  //
+  //   For non-template functions, default arguments can be added in
+  //   later declarations of a function in the same
+  //   scope. Declarations in different scopes have completely
+  //   distinct sets of default arguments. That is, declarations in
+  //   inner scopes do not acquire default arguments from
+  //   declarations in outer scopes, and vice versa. In a given
+  //   function declaration, all parameters subsequent to a
+  //   parameter with a default argument shall have default
+  //   arguments supplied in this or previous declarations. A
+  //   default argument shall not be redefined by a later
+  //   declaration (not even to the same value).
+  for (unsigned p = 0, NumParams = Old->getNumParams(); p < NumParams; ++p) {
+    ParmVarDecl *OldParam = Old->getParamDecl(p);
+    ParmVarDecl *NewParam = New->getParamDecl(p);
+
+    if(OldParam->getDefaultArg() && NewParam->getDefaultArg()) {
+      Diag(NewParam->getLocation(), 
+           diag::err_param_default_argument_redefinition,
+           NewParam->getDefaultArg()->getSourceRange());
+      Diag(OldParam->getLocation(), diag::err_previous_definition);
+    } else if (OldParam->getDefaultArg()) {
+      // Merge the old default argument into the new parameter
+      NewParam->setDefaultArg(OldParam->getDefaultArg());
+    }
+  }
+
+  return New;  
+}
+
+/// CheckCXXDefaultArguments - Verify that the default arguments for a
+/// function declaration are well-formed according to C++
+/// [dcl.fct.default].
+void Sema::CheckCXXDefaultArguments(FunctionDecl *FD) {
+  unsigned NumParams = FD->getNumParams();
+  unsigned p;
+
+  // Find first parameter with a default argument
+  for (p = 0; p < NumParams; ++p) {
+    ParmVarDecl *Param = FD->getParamDecl(p);
+    if (Param->getDefaultArg())
+      break;
+  }
+
+  // C++ [dcl.fct.default]p4:
+  //   In a given function declaration, all parameters
+  //   subsequent to a parameter with a default argument shall
+  //   have default arguments supplied in this or previous
+  //   declarations. A default argument shall not be redefined
+  //   by a later declaration (not even to the same value).
+  unsigned LastMissingDefaultArg = 0;
+  for(; p < NumParams; ++p) {
+    ParmVarDecl *Param = FD->getParamDecl(p);
+    if (!Param->getDefaultArg()) {
+      if (Param->getIdentifier())
+        Diag(Param->getLocation(), 
+             diag::err_param_default_argument_missing_name,
+             Param->getIdentifier()->getName());
+      else
+        Diag(Param->getLocation(), 
+             diag::err_param_default_argument_missing);
+    
+      LastMissingDefaultArg = p;
+    }
+  }
+
+  if (LastMissingDefaultArg > 0) {
+    // Some default arguments were missing. Clear out all of the
+    // default arguments up to (and including) the last missing
+    // default argument, so that we leave the function parameters
+    // in a semantically valid state.
+    for (p = 0; p <= LastMissingDefaultArg; ++p) {
+      ParmVarDecl *Param = FD->getParamDecl(p);
+      if (Param->getDefaultArg()) {
+        delete Param->getDefaultArg();
+        Param->setDefaultArg(0);
+      }
+    }
+  }
+}





More information about the cfe-commits mailing list